aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/CONTRIBUTING.md21
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml4
-rw-r--r--ARCHITECTURE.md45
-rw-r--r--CHANGELOG.md10
-rw-r--r--FAQ.md2
-rw-r--r--README.md16
-rw-r--r--client/src/app/+about/about-follows/about-follows.component.html22
-rw-r--r--client/src/app/+about/about-follows/about-follows.component.scss14
-rw-r--r--client/src/app/+about/about-follows/about-follows.component.ts103
-rw-r--r--client/src/app/+about/about-routing.module.ts10
-rw-r--r--client/src/app/+about/about.component.html4
-rw-r--r--client/src/app/+about/about.module.ts2
-rw-r--r--client/src/app/+accounts/account-video-channels/account-video-channels.component.html32
-rw-r--r--client/src/app/+accounts/account-video-channels/account-video-channels.component.scss31
-rw-r--r--client/src/app/+accounts/account-video-channels/account-video-channels.component.ts71
-rw-r--r--client/src/app/+accounts/account-videos/account-videos.component.ts4
-rw-r--r--client/src/app/+accounts/accounts-routing.module.ts2
-rw-r--r--client/src/app/+accounts/accounts.component.html4
-rw-r--r--client/src/app/+admin/admin.module.ts3
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html8
-rw-r--r--client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts1
-rw-r--r--client/src/app/+admin/follows/followers-list/followers-list.component.ts2
-rw-r--r--client/src/app/+admin/follows/following-add/following-add.component.ts2
-rw-r--r--client/src/app/+admin/follows/following-list/following-list.component.ts2
-rw-r--r--client/src/app/+admin/follows/index.ts1
-rw-r--r--client/src/app/+admin/follows/shared/index.ts1
-rw-r--r--client/src/app/+admin/users/user-edit/user-edit.ts5
-rw-r--r--client/src/app/+my-account/my-account-history/my-account-history.component.ts2
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html7
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts5
-rw-r--r--client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts15
-rw-r--r--client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-create.component.ts3
-rw-r--r--client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.component.html10
-rw-r--r--client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.ts4
-rw-r--r--client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-update.component.ts47
-rw-r--r--client/src/app/+my-account/my-account-videos/my-account-videos.component.html2
-rw-r--r--client/src/app/+signup/+register/custom-stepper.component.html25
-rw-r--r--client/src/app/+signup/+register/custom-stepper.component.scss66
-rw-r--r--client/src/app/+signup/+register/custom-stepper.component.ts19
-rw-r--r--client/src/app/+signup/+register/register-routing.module.ts (renamed from client/src/app/signup/signup-routing.module.ts)17
-rw-r--r--client/src/app/+signup/+register/register-step-channel.component.html50
-rw-r--r--client/src/app/+signup/+register/register-step-channel.component.ts40
-rw-r--r--client/src/app/+signup/+register/register-step-user.component.html54
-rw-r--r--client/src/app/+signup/+register/register-step-user.component.ts37
-rw-r--r--client/src/app/+signup/+register/register.component.html41
-rw-r--r--client/src/app/+signup/+register/register.component.scss (renamed from client/src/app/signup/signup.component.scss)33
-rw-r--r--client/src/app/+signup/+register/register.component.ts89
-rw-r--r--client/src/app/+signup/+register/register.module.ts33
-rw-r--r--client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.html (renamed from client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.html)0
-rw-r--r--client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.scss (renamed from client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.scss)0
-rw-r--r--client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts (renamed from client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts)0
-rw-r--r--client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.html (renamed from client/src/app/+verify-account/verify-account-email/verify-account-email.component.html)6
-rw-r--r--client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts (renamed from client/src/app/+verify-account/verify-account-email/verify-account-email.component.ts)3
-rw-r--r--client/src/app/+signup/+verify-account/verify-account-routing.module.ts (renamed from client/src/app/+verify-account/verify-account-routing.module.ts)8
-rw-r--r--client/src/app/+signup/+verify-account/verify-account.module.ts25
-rw-r--r--client/src/app/+signup/shared/signup-shared.module.ts21
-rw-r--r--client/src/app/+signup/shared/signup-success.component.html16
-rw-r--r--client/src/app/+signup/shared/signup-success.component.scss76
-rw-r--r--client/src/app/+signup/shared/signup-success.component.ts10
-rw-r--r--client/src/app/+verify-account/index.ts2
-rw-r--r--client/src/app/+verify-account/verify-account.module.ts27
-rw-r--r--client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts5
-rw-r--r--client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts2
-rw-r--r--client/src/app/app-routing.module.ts6
-rw-r--r--client/src/app/app.module.ts2
-rw-r--r--client/src/app/core/core.module.ts3
-rw-r--r--client/src/app/core/routing/redirect.service.ts9
-rw-r--r--client/src/app/core/routing/unlogged-guard.service.ts25
-rw-r--r--client/src/app/shared/actor/actor.model.ts2
-rw-r--r--client/src/app/shared/buttons/button.component.scss13
-rw-r--r--client/src/app/shared/buttons/button.component.ts2
-rw-r--r--client/src/app/shared/buttons/delete-button.component.html2
-rw-r--r--client/src/app/shared/buttons/edit-button.component.html2
-rw-r--r--client/src/app/shared/forms/peertube-checkbox.component.scss3
-rw-r--r--client/src/app/shared/forms/reactive-file.component.html7
-rw-r--r--client/src/app/shared/forms/reactive-file.component.scss10
-rw-r--r--client/src/app/shared/forms/reactive-file.component.ts2
-rw-r--r--client/src/app/shared/images/image-upload.component.html9
-rw-r--r--client/src/app/shared/images/image-upload.component.scss18
-rw-r--r--client/src/app/shared/images/preview-upload.component.html13
-rw-r--r--client/src/app/shared/images/preview-upload.component.scss27
-rw-r--r--client/src/app/shared/images/preview-upload.component.ts (renamed from client/src/app/shared/images/image-upload.component.ts)17
-rw-r--r--client/src/app/shared/instance/follow.service.ts (renamed from client/src/app/+admin/follows/shared/follow.service.ts)8
-rw-r--r--client/src/app/shared/shared.module.ts9
-rw-r--r--client/src/app/shared/users/user.service.ts3
-rw-r--r--client/src/app/shared/video-channel/video-channel.service.ts17
-rw-r--r--client/src/app/shared/video/abstract-video-list.html20
-rw-r--r--client/src/app/shared/video/abstract-video-list.scss36
-rw-r--r--client/src/app/shared/video/abstract-video-list.ts80
-rw-r--r--client/src/app/shared/video/modals/video-download.component.ts8
-rw-r--r--client/src/app/shared/video/video-details.model.ts3
-rw-r--r--client/src/app/shared/video/video-edit.model.ts5
-rw-r--r--client/src/app/shared/video/video.model.ts2
-rw-r--r--client/src/app/shared/video/videos-selection.component.ts2
-rw-r--r--client/src/app/signup/index.ts3
-rw-r--r--client/src/app/signup/signup.component.html72
-rw-r--r--client/src/app/signup/signup.component.ts78
-rw-r--r--client/src/app/signup/signup.module.ts24
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.html14
-rw-r--r--client/src/app/videos/+video-edit/shared/video-edit.component.ts8
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html2
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts1
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html2
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-send.ts1
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-upload.component.html23
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-upload.component.scss17
-rw-r--r--client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts108
-rw-r--r--client/src/app/videos/+video-edit/video-update.component.html2
-rw-r--r--client/src/app/videos/+video-edit/video-update.component.ts15
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.ts77
-rw-r--r--client/src/app/videos/video-list/video-local.component.ts2
-rw-r--r--client/src/app/videos/video-list/video-overview.component.html6
-rw-r--r--client/src/app/videos/video-list/video-overview.component.scss60
-rw-r--r--client/src/app/videos/video-list/video-recently-added.component.ts3
-rw-r--r--client/src/app/videos/video-list/video-trending.component.ts2
-rw-r--r--client/src/app/videos/video-list/video-user-subscriptions.component.ts3
-rw-r--r--client/src/assets/player/peertube-player-manager.ts13
-rw-r--r--client/src/sass/include/_miniature.scss97
-rw-r--r--client/src/sass/include/_mixins.scss7
-rw-r--r--config/default.yaml9
-rw-r--r--config/production.yaml.example3
-rw-r--r--config/test-2.yaml1
-rw-r--r--config/test.yaml2
-rw-r--r--package.json39
-rwxr-xr-xscripts/clean/server/test.sh7
-rwxr-xr-xscripts/create-transcoding-job.ts13
-rwxr-xr-xscripts/setup/cli.sh16
-rwxr-xr-xscripts/test.sh2
-rwxr-xr-xscripts/travis.sh9
-rw-r--r--server/assets/default-audio-background.jpgbin0 -> 14048 bytes
-rw-r--r--server/controllers/api/accounts.ts16
-rw-r--r--server/controllers/api/config.ts3
-rw-r--r--server/controllers/api/users/index.ts13
-rw-r--r--server/controllers/api/video-channel.ts37
-rw-r--r--server/controllers/api/video-playlist.ts6
-rw-r--r--server/controllers/api/videos/index.ts54
-rw-r--r--server/controllers/static.ts2
-rw-r--r--server/helpers/custom-validators/accounts.ts11
-rw-r--r--server/helpers/custom-validators/activitypub/video-comments.ts3
-rw-r--r--server/helpers/custom-validators/video-channels.ts9
-rw-r--r--server/helpers/express-utils.ts13
-rw-r--r--server/helpers/ffmpeg-utils.ts180
-rw-r--r--server/initializers/config.ts9
-rw-r--r--server/initializers/constants.ts70
-rw-r--r--server/initializers/installer.ts4
-rw-r--r--server/initializers/migrations/0385-remove-actor-uuid.ts19
-rw-r--r--server/lib/activitypub/actor.ts33
-rw-r--r--server/lib/activitypub/crawl.ts19
-rw-r--r--server/lib/activitypub/process/process-announce.ts15
-rw-r--r--server/lib/activitypub/process/process-create.ts29
-rw-r--r--server/lib/activitypub/process/process-delete.ts8
-rw-r--r--server/lib/activitypub/process/process-update.ts4
-rw-r--r--server/lib/activitypub/video-comments.ts4
-rw-r--r--server/lib/emailer.ts66
-rw-r--r--server/lib/files-cache/videos-preview-cache.ts2
-rw-r--r--server/lib/job-queue/handlers/video-file-import.ts4
-rw-r--r--server/lib/job-queue/handlers/video-import.ts1
-rw-r--r--server/lib/job-queue/handlers/video-transcoding.ts56
-rw-r--r--server/lib/thumbnail.ts8
-rw-r--r--server/lib/user.ts34
-rw-r--r--server/lib/video-channel.ts16
-rw-r--r--server/lib/video-transcoding.ts97
-rw-r--r--server/middlewares/validators/feeds.ts13
-rw-r--r--server/middlewares/validators/users.ts28
-rw-r--r--server/middlewares/validators/videos/video-channels.ts16
-rw-r--r--server/middlewares/validators/videos/video-playlists.ts15
-rw-r--r--server/middlewares/validators/videos/videos.ts8
-rw-r--r--server/models/account/account.ts19
-rw-r--r--server/models/activitypub/actor.ts14
-rw-r--r--server/models/video/thumbnail.ts8
-rw-r--r--server/models/video/video-channel.ts34
-rw-r--r--server/models/video/video-file.ts5
-rw-r--r--server/models/video/video.ts23
-rw-r--r--server/tests/api/activitypub/client.ts11
-rw-r--r--server/tests/api/activitypub/fetch.ts17
-rw-r--r--server/tests/api/activitypub/refresher.ts46
-rw-r--r--server/tests/api/activitypub/security.ts106
-rw-r--r--server/tests/api/check-params/config.ts1
-rw-r--r--server/tests/api/check-params/users.ts35
-rw-r--r--server/tests/api/check-params/video-channels.ts36
-rw-r--r--server/tests/api/check-params/video-playlists.ts12
-rw-r--r--server/tests/api/index-1.ts3
-rw-r--r--server/tests/api/index-2.ts2
-rw-r--r--server/tests/api/index-3.ts1
-rw-r--r--server/tests/api/index-4.ts2
-rw-r--r--server/tests/api/index.ts12
-rw-r--r--server/tests/api/notifications/index.ts2
-rw-r--r--server/tests/api/notifications/user-notifications.ts41
-rw-r--r--server/tests/api/redundancy/redundancy.ts34
-rw-r--r--server/tests/api/search/search-activitypub-video-channels.ts39
-rw-r--r--server/tests/api/search/search-activitypub-videos.ts31
-rw-r--r--server/tests/api/search/search-videos.ts10
-rw-r--r--server/tests/api/server/config.ts33
-rw-r--r--server/tests/api/server/contact-form.ts7
-rw-r--r--server/tests/api/server/email.ts36
-rw-r--r--server/tests/api/server/follow-constraints.ts46
-rw-r--r--server/tests/api/server/follows-moderation.ts20
-rw-r--r--server/tests/api/server/follows.ts61
-rw-r--r--server/tests/api/server/handle-down.ts76
-rw-r--r--server/tests/api/server/jobs.ts2
-rw-r--r--server/tests/api/server/logs.ts2
-rw-r--r--server/tests/api/travis-1.sh10
-rw-r--r--server/tests/api/travis-2.sh9
-rw-r--r--server/tests/api/travis-3.sh8
-rw-r--r--server/tests/api/travis-4.sh9
-rw-r--r--server/tests/api/users/blocklist.ts28
-rw-r--r--server/tests/api/users/user-subscriptions.ts34
-rw-r--r--server/tests/api/users/users-multiple-servers.ts54
-rw-r--r--server/tests/api/users/users-verification.ts5
-rw-r--r--server/tests/api/users/users.ts20
-rw-r--r--server/tests/api/videos/multiple-servers.ts45
-rw-r--r--server/tests/api/videos/services.ts14
-rw-r--r--server/tests/api/videos/single-server.ts23
-rw-r--r--server/tests/api/videos/video-abuse.ts9
-rw-r--r--server/tests/api/videos/video-change-ownership.ts8
-rw-r--r--server/tests/api/videos/video-channels.ts116
-rw-r--r--server/tests/api/videos/video-comments.ts6
-rw-r--r--server/tests/api/videos/video-hls.ts54
-rw-r--r--server/tests/api/videos/video-playlists.ts38
-rw-r--r--server/tests/api/videos/video-privacy.ts26
-rw-r--r--server/tests/api/videos/video-transcoder.ts89
-rw-r--r--server/tests/api/videos/videos-views-cleaner.ts16
-rw-r--r--server/tests/cli/optimize-old-videos.ts10
-rw-r--r--server/tests/feeds/feeds.ts76
-rw-r--r--server/tests/fixtures/preview.jpgbin4215 -> 6868 bytes
-rw-r--r--server/tests/fixtures/sample.oggbin0 -> 105243 bytes
-rw-r--r--server/tests/fixtures/video_short1-preview.webm.jpgbin10181 -> 22654 bytes
-rw-r--r--server/tools/package.json12
-rw-r--r--server/tools/peertube-watch.ts47
-rw-r--r--[-rwxr-xr-x]server/tools/peertube.ts0
-rw-r--r--server/tools/tsconfig.json4
-rw-r--r--server/tools/yarn.lock1970
-rw-r--r--shared/core-utils/miscs/date.ts67
-rw-r--r--shared/extra-utils/miscs/sql.ts35
-rw-r--r--shared/extra-utils/search/videos.ts19
-rw-r--r--shared/extra-utils/server/config.ts1
-rw-r--r--shared/extra-utils/server/follows.ts26
-rw-r--r--shared/extra-utils/server/servers.ts4
-rw-r--r--shared/extra-utils/users/accounts.ts4
-rw-r--r--shared/extra-utils/users/user-notifications.ts2
-rw-r--r--shared/extra-utils/users/users.ts39
-rw-r--r--shared/extra-utils/videos/video-channels.ts37
-rw-r--r--shared/extra-utils/videos/video-playlists.ts4
-rw-r--r--shared/extra-utils/videos/videos.ts6
-rw-r--r--shared/models/activitypub/activitypub-actor.ts1
-rw-r--r--shared/models/actors/account.model.ts1
-rw-r--r--shared/models/actors/actor.model.ts1
-rw-r--r--shared/models/server/custom-config.model.ts1
-rw-r--r--shared/models/users/user-register.model.ts10
-rw-r--r--shared/models/videos/channel/video-channel-update.model.ts4
-rw-r--r--shared/models/videos/channel/video-channel.model.ts1
-rw-r--r--shared/models/videos/playlist/video-playlist-update.model.ts4
-rw-r--r--shared/models/videos/video-resolution.enum.ts10
-rw-r--r--support/doc/api/openapi.yaml182
-rw-r--r--support/doc/api/quickstart.md2
-rw-r--r--support/doc/development/client/code.md67
-rw-r--r--support/doc/development/client/components-tree.pngbin22104 -> 0 bytes
-rw-r--r--support/doc/development/client/components-tree.svg2
-rw-r--r--support/doc/development/client/components-tree.xml1
-rw-r--r--support/doc/development/server/code.md58
-rw-r--r--support/doc/development/server/peertube-architecture-server.xml1
-rw-r--r--support/doc/development/server/upload-video.pngbin34643 -> 0 bytes
-rw-r--r--support/doc/production.md3
-rw-r--r--support/doc/tools.md14
-rw-r--r--support/docker/production/.env3
-rw-r--r--support/docker/production/config/custom-environment-variables.yaml3
-rw-r--r--support/docker/production/docker-compose.yml7
-rw-r--r--tsconfig.json1
-rw-r--r--yarn.lock2853
270 files changed, 6355 insertions, 3940 deletions
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index b3847b8d7..822449b3a 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -9,8 +9,6 @@ Interested in contributing? Awesome!
9 * [Write documentation](#write-documentation) 9 * [Write documentation](#write-documentation)
10 * [Develop](#develop) 10 * [Develop](#develop)
11 * [Improve the website](#improve-the-website) 11 * [Improve the website](#improve-the-website)
12 * [Troubleshooting](#troubleshooting)
13 * [Tutorials](#tutorials)
14 12
15## Translate 13## Translate
16 14
@@ -61,10 +59,11 @@ Make sure that you have followed
61[the steps](/support/doc/dependencies.md) 59[the steps](/support/doc/dependencies.md)
62to install the dependencies. 60to install the dependencies.
63 61
64Then clone the sources and install node modules: 62Fork the github repository,
63and then clone the sources and install node modules:
65 64
66``` 65```
67$ git clone https://github.com/Chocobozzz/PeerTube 66$ git clone https://github.com/YOUR_GITHUB_USERNAME/PeerTube
68$ cd PeerTube 67$ cd PeerTube
69$ yarn install --pure-lockfile 68$ yarn install --pure-lockfile
70``` 69```
@@ -101,7 +100,7 @@ You can get a complete PeerTube development setup with Gitpod, a free one-click
101 100
102### Server side 101### Server side
103 102
104You can find a documentation of the server code/architecture [here](/support/doc/development/server/code.md). 103You can find a documentation of the server code/architecture [here](https://docs.joinpeertube.org/#/contribute-architecture?id=server-code).
105 104
106To develop on the server-side: 105To develop on the server-side:
107 106
@@ -115,8 +114,8 @@ restart.
115 114
116### Client side 115### Client side
117 116
118You can find a documentation of the server code/architecture 117You can find a documentation of the client code/architecture
119[here](/support/doc/development/client/code.md). 118[here](https://docs.joinpeertube.org/#/contribute-architecture?id=client-code).
120 119
121 120
122To develop on the client side: 121To develop on the client side:
@@ -193,11 +192,3 @@ $ npm run mocha -- --exit --require ts-node/register/type-check --bail server/te
193 192
194Instance configurations are in `config/test-{1,2,3,4,5,6}.yaml`. 193Instance configurations are in `config/test-{1,2,3,4,5,6}.yaml`.
195Note that only instance 2 has transcoding enabled. 194Note that only instance 2 has transcoding enabled.
196
197### Troubleshooting
198
199Please check out the issues and [list of common errors](https://docs.joinpeertube.org/lang/en/devdocs/troubleshooting.html).
200
201### Tutorials
202
203Please check out the related section in the [development documentation](https://docs.joinpeertube.org/lang/en/devdocs/index.html#tutorials). Contribute tutorials at [framagit.org/framasoft/peertube/documentation](https://framagit.org/framasoft/peertube/documentation).
diff --git a/.gitignore b/.gitignore
index 8cd04eea1..3a91facb4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
1# NPM instalation 1# NPM instalation
2/node_modules/ 2/node_modules/
3/server/tools/node_modules
3*npm-debug.log 4*npm-debug.log
4 5
5# Testing 6# Testing
diff --git a/.travis.yml b/.travis.yml
index 5fa41fb43..8b3ec94d9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,8 +29,8 @@ install:
29 - CC=gcc-4.9 CXX=g++-4.9 yarn install 29 - CC=gcc-4.9 CXX=g++-4.9 yarn install
30 30
31before_script: 31before_script:
32 - wget --no-check-certificate "https://download.cpy.re/ffmpeg/ffmpeg-release-4.0.2-64bit-static.tar.xz" 32 - wget --no-check-certificate "https://download.cpy.re/ffmpeg/ffmpeg-release-4.0.3-64bit-static.tar.xz"
33 - tar xf ffmpeg-release-4.0.2-64bit-static.tar.xz 33 - tar xf ffmpeg-release-4.0.3-64bit-static.tar.xz
34 - mkdir -p $HOME/bin 34 - mkdir -p $HOME/bin
35 - cp ffmpeg-*/{ffmpeg,ffprobe} $HOME/bin 35 - cp ffmpeg-*/{ffmpeg,ffprobe} $HOME/bin
36 - export PATH=$HOME/bin:$PATH 36 - export PATH=$HOME/bin:$PATH
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
deleted file mode 100644
index f3254d2d6..000000000
--- a/ARCHITECTURE.md
+++ /dev/null
@@ -1,45 +0,0 @@
1# Architecture
2
3## Vocabulary
4
5 - **Fediverse:** several servers following one another, several users
6 following each other. Designates federated communities in general.
7 - **Vidiverse:** same as Fediverse, but federating videos specifically.
8 - **Instance:** a server which runs PeerTube in the fediverse.
9 - **Origin instance:** the instance on which the video was uploaded and which
10 is seeding (through the WebSeed protocol) the video.
11 - **Cache instance:** an instance that decided to make available a WebSeed
12 of its own for a video originating from another instance. It sends a `ptCache`
13 activity to notify the origin instance, which will then update its list of
14 WebSeeds for the video.
15 - **Following:** the action of a PeerTube instance which will follow another
16 instance (subscribe to its videos).
17
18## Base
19
20### Communications
21 * All the communication between the instances are signed with [Linked Data
22 Signatures](https://w3c-dvcg.github.io/ld-signatures/) with the private key
23 of the account that authored the action.
24 * We use the [ActivityPub](https://www.w3.org/TR/activitypub/) protocol (only
25 server-server for now). Object models could be found in
26 [shared/models/activitypub
27 directory](/shared/models/activitypub).
28 * All the requests are retried several times if they fail.
29
30### Instance
31 * An instance has a websocket tracker which is responsible for all videos
32 uploaded by its users.
33 * An instance has an administrator that can follow other instances.
34 * An instance can be configured to follow back automatically.
35 * An instance can blacklist other instances (only used in "follow back"
36 mode).
37 * An instance cannot choose which other instances follow it, but it can
38 decide to **reject all** followers.
39 * After having uploaded a video, the instance seeds it (WebSeed protocol).
40 * If a user wants to watch a video, they ask its instance the magnet URI and
41 the frontend adds the torrent (with WebTorrent), creates the HTML5 video
42 player and streams the file into it.
43 * A user watching a video seeds it too (BitTorrent). Thus another user who is
44 watching the same video can get the data from the origin server and other
45 users watching it.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 363fae00d..6a3b2d7a5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -333,8 +333,8 @@ and update your [.env](https://github.com/Chocobozzz/PeerTube/blob/develop/suppo
333 333
334### Maintenance 334### Maintenance
335 335
336 * Improve REST API documentation: https://docs.joinpeertube.org/api.html ([@rigelk](https://github.com/rigelk)) 336 * Improve REST API documentation ([@rigelk](https://github.com/rigelk))
337 * Add basic ActivityPub documentation: https://docs.joinpeertube.org/lang/en/devdocs/federation.html ([@rigelk](https://github.com/rigelk)) 337 * Add basic ActivityPub documentation ([@rigelk](https://github.com/rigelk))
338 * Add CLI option to run PeerTube without client ([@rigelk](https://github.com/rigelk)) 338 * Add CLI option to run PeerTube without client ([@rigelk](https://github.com/rigelk))
339 * Add manpage to peertube CLI ([@rigelk](https://github.com/rigelk)) 339 * Add manpage to peertube CLI ([@rigelk](https://github.com/rigelk))
340 * Make backups of files in optimize-old-videos script ([@Nutomic](https://github.com/nutomic)) 340 * Make backups of files in optimize-old-videos script ([@Nutomic](https://github.com/nutomic))
@@ -419,8 +419,8 @@ and update your [.env](https://github.com/Chocobozzz/PeerTube/blob/develop/suppo
419 419
420### Maintenance 420### Maintenance
421 421
422 * Improve REST API documentation: https://docs.joinpeertube.org/api.html ([@rigelk](https://github.com/rigelk)) 422 * Improve REST API documentation ([@rigelk](https://github.com/rigelk))
423 * Add basic ActivityPub documentation: https://docs.joinpeertube.org/lang/en/devdocs/federation.html ([@rigelk](https://github.com/rigelk)) 423 * Add basic ActivityPub documentation ([@rigelk](https://github.com/rigelk))
424 * Add CLI option to run PeerTube without client ([@rigelk](https://github.com/rigelk)) 424 * Add CLI option to run PeerTube without client ([@rigelk](https://github.com/rigelk))
425 * Add manpage to peertube CLI ([@rigelk](https://github.com/rigelk)) 425 * Add manpage to peertube CLI ([@rigelk](https://github.com/rigelk))
426 * Make backups of files in optimize-old-videos script ([@Nutomic](https://github.com/nutomic)) 426 * Make backups of files in optimize-old-videos script ([@Nutomic](https://github.com/nutomic))
@@ -634,7 +634,7 @@ This release could contain bugs. Don't expect a stable v1.1.0 until December :)
634 634
635### Features 635### Features
636 636
637 * Video redundancy system (experimental, see [the doc](https://docs.joinpeertube.org/lang/en/devdocs/architecture.html#redundancy-between-instances)) 637 * Video redundancy system (experimental)
638 * Add peertube script (see [the doc](/support/doc/tools.md#cli-wrapper)) ([@rigelk](https://github.com/rigelk)) 638 * Add peertube script (see [the doc](/support/doc/tools.md#cli-wrapper)) ([@rigelk](https://github.com/rigelk))
639 * Improve download modal ([@rigelk](https://github.com/rigelk)) 639 * Improve download modal ([@rigelk](https://github.com/rigelk))
640 * Add redirect after login ([@BO41](https://github.com/BO41)) 640 * Add redirect after login ([@BO41](https://github.com/BO41))
diff --git a/FAQ.md b/FAQ.md
index 7d8be96a7..1a3b1847b 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -58,7 +58,7 @@ is named "Framatube".
58 58
59Yes, the origin server always seeds videos uploaded on it thanks to 59Yes, the origin server always seeds videos uploaded on it thanks to
60[Webseed](http://www.bittorrent.org/beps/bep_0019.html). 60[Webseed](http://www.bittorrent.org/beps/bep_0019.html).
61It can also be helped by other servers using [redundancy](https://docs.joinpeertube.org/lang/en/devdocs/architecture.html#redundancy-between-instances). 61It can also be helped by other servers using [redundancy](https://docs.joinpeertube.org/#/contribute-architecture?id=redundancy-between-instances).
62 62
63 63
64## What is WebSeed? 64## What is WebSeed?
diff --git a/README.md b/README.md
index a5060cf0d..3edaeef2f 100644
--- a/README.md
+++ b/README.md
@@ -115,7 +115,7 @@ Be it as a user or an instance administrator, you can decide what your experienc
115 115
116<h3 align="right">Communities that help each other</h3> 116<h3 align="right">Communities that help each other</h3>
117<p align="right"> 117<p align="right">
118In addition to visitors using WebTorrent to share the load among them, instances can help each other by caching one another's videos. This way even small instances have a way to show content to a wider audience, as they will be shouldered by friend instances (more about that in our <a href="https://docs.joinpeertube.org/lang/en/devdocs/architecture.html#redundancy-between-instances">redundancy guide</a>). 118In addition to visitors using WebTorrent to share the load among them, instances can help each other by caching one another's videos. This way even small instances have a way to show content to a wider audience, as they will be shouldered by friend instances (more about that in our <a href="https://docs.joinpeertube.org/#/contribute-architecture?id=redundancy-between-instances">redundancy guide</a>).
119</p> 119</p>
120<p align="right"> 120<p align="right">
121Content creators can get help from their viewers in the simplest way possible: a support button showing a message linking to their donation accounts or really anything else. No more pay-per-view and advertisements that hurt visitors and <strike>incentivize</strike> alter creativity (more about that in our <a href="./FAQ.md">FAQ</a>). 121Content creators can get help from their viewers in the simplest way possible: a support button showing a message linking to their donation accounts or really anything else. No more pay-per-view and advertisements that hurt visitors and <strike>incentivize</strike> alter creativity (more about that in our <a href="./FAQ.md">FAQ</a>).
@@ -151,9 +151,9 @@ Feel free to reach out if you have any questions or ideas! :speech_balloon:
151 * **yarn >= 1.x** 151 * **yarn >= 1.x**
152 * **FFmpeg >= 3.x** 152 * **FFmpeg >= 3.x**
153 153
154See the [production guide](/support/doc/production.md), which is the recommended way. 154See the [production guide](/support/doc/production.md), which is the recommended way to install or upgrade PeerTube. For hardware requirements, see [Should I have a big server to run PeerTube?](https://github.com/Chocobozzz/PeerTube/blob/develop/FAQ.md#should-i-have-a-big-server-to-run-peertube) in the FAQ.
155 155
156See the [community packages](https://docs.joinpeertube.org/lang/en/docs/install.html), which cover various platforms (including [YunoHost](https://install-app.yunohost.org/?app=peertube) and [Docker](/support/doc/docker.md)). 156See the [community packages](https://docs.joinpeertube.org/#/install-unofficial), which cover various platforms (including [YunoHost](https://install-app.yunohost.org/?app=peertube) and [Docker](/support/doc/docker.md)).
157 157
158:book: Documentation 158:book: Documentation
159---------------------------------------------------------------- 159----------------------------------------------------------------
@@ -162,13 +162,13 @@ If you have a question, please try to find the answer in the [FAQ](/FAQ.md) firs
162 162
163### User documentation 163### User documentation
164 164
165See the [user documentation](https://docs.joinpeertube.org/lang/en/userdocs/). 165See the [user documentation](https://docs.joinpeertube.org/#/use-setup-account).
166 166
167### Admin documentation 167### Admin documentation
168 168
169See [how to create your own instance](#package-create-your-own-instance). 169See [how to create your own instance](#package-create-your-own-instance).
170 170
171See the more general [admin documentation](https://docs.joinpeertube.org/lang/en/docs/). 171See the more general [admin documentation](https://docs.joinpeertube.org/#/admin-following-instances).
172 172
173#### Tools 173#### Tools
174 174
@@ -178,13 +178,13 @@ See the more general [admin documentation](https://docs.joinpeertube.org/lang/en
178 178
179### Technical documentation 179### Technical documentation
180 180
181See the [architecture blueprint](https://docs.joinpeertube.org/lang/en/devdocs/architecture.html) for a more detailed explanation of the architectural choices. 181See the [architecture blueprint](https://docs.joinpeertube.org/#/contribute-architecture) for a more detailed explanation of the architectural choices.
182 182
183See our REST API documentation: 183See our REST API documentation:
184 * OpenAPI 3.0.0 schema: [/support/doc/api/openapi.yaml](/support/doc/api/openapi.yaml) 184 * OpenAPI 3.0.0 schema: [/support/doc/api/openapi.yaml](/support/doc/api/openapi.yaml)
185 * Spec explorer: [docs.joinpeertube.org/api.html](http://docs.joinpeertube.org/api.html) 185 * Spec explorer: [docs.joinpeertube.org/#/api-rest-reference.html](https://docs.joinpeertube.org/#/api-rest-reference.html)
186 186
187See our [ActivityPub documentation](https://docs.joinpeertube.org/lang/en/devdocs/federation.html). 187See our [ActivityPub documentation](https://docs.joinpeertube.org/#/api-activitypub).
188 188
189:heart: Supports of our crowdfunding 189:heart: Supports of our crowdfunding
190---------------------------------------------------------------- 190----------------------------------------------------------------
diff --git a/client/src/app/+about/about-follows/about-follows.component.html b/client/src/app/+about/about-follows/about-follows.component.html
new file mode 100644
index 000000000..18689bbf7
--- /dev/null
+++ b/client/src/app/+about/about-follows/about-follows.component.html
@@ -0,0 +1,22 @@
1<div class="row" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()">
2 <div class="col-xl-6 col-md-12">
3 <div i18n class="subtitle">Followers</div>
4
5 <div i18n class="no-results" *ngIf="followersPagination.totalItems === 0">This instance does not have followers.</div>
6
7 <a *ngFor="let follower of followers" [href]="buildLink(follower)" target="_blank" rel="noopener noreferrer">
8 {{ follower }}
9 </a>
10 </div>
11
12 <div class="col-xl-6 col-md-12">
13 <div i18n class="subtitle">Followings</div>
14
15 <div i18n class="no-results" *ngIf="followingsPagination.totalItems === 0">This instance does not have followings.</div>
16
17 <a *ngFor="let following of followings" [href]="buildLink(following)" target="_blank" rel="noopener noreferrer">
18 {{ following }}
19 </a>
20 </div>
21
22</div>
diff --git a/client/src/app/+about/about-follows/about-follows.component.scss b/client/src/app/+about/about-follows/about-follows.component.scss
new file mode 100644
index 000000000..e0d597a96
--- /dev/null
+++ b/client/src/app/+about/about-follows/about-follows.component.scss
@@ -0,0 +1,14 @@
1@import '_variables';
2@import '_mixins';
3
4.subtitle {
5 font-size: 18px;
6 font-weight: $font-semibold;
7 margin-bottom: 20px;
8}
9
10a {
11 display: block;
12 width: fit-content;
13 margin-top: 3px;
14}
diff --git a/client/src/app/+about/about-follows/about-follows.component.ts b/client/src/app/+about/about-follows/about-follows.component.ts
new file mode 100644
index 000000000..f0e1375d6
--- /dev/null
+++ b/client/src/app/+about/about-follows/about-follows.component.ts
@@ -0,0 +1,103 @@
1import { Component, OnInit } from '@angular/core'
2import { FollowService } from '@app/shared/instance/follow.service'
3import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
4import { Notifier } from '@app/core'
5import { RestService } from '@app/shared'
6import { SortMeta } from 'primeng/api'
7
8@Component({
9 selector: 'my-about-follows',
10 templateUrl: './about-follows.component.html',
11 styleUrls: [ './about-follows.component.scss' ]
12})
13
14export class AboutFollowsComponent implements OnInit {
15 followers: string[] = []
16 followings: string[] = []
17
18 followersPagination: ComponentPagination = {
19 currentPage: 1,
20 itemsPerPage: 40,
21 totalItems: null
22 }
23
24 followingsPagination: ComponentPagination = {
25 currentPage: 1,
26 itemsPerPage: 40,
27 totalItems: null
28 }
29
30 sort: SortMeta = {
31 field: 'createdAt',
32 order: -1
33 }
34
35 constructor (
36 private restService: RestService,
37 private notifier: Notifier,
38 private followService: FollowService
39 ) { }
40
41 ngOnInit () {
42 this.loadMoreFollowers()
43
44 this.loadMoreFollowings()
45 }
46
47 onNearOfBottom () {
48 this.onNearOfFollowersBottom()
49
50 this.onNearOfFollowingsBottom()
51 }
52
53 onNearOfFollowersBottom () {
54 if (!hasMoreItems(this.followersPagination)) return
55
56 this.followersPagination.currentPage += 1
57 this.loadMoreFollowers()
58 }
59
60 onNearOfFollowingsBottom () {
61 if (!hasMoreItems(this.followingsPagination)) return
62
63 this.followingsPagination.currentPage += 1
64 this.loadMoreFollowings()
65 }
66
67 buildLink (host: string) {
68 return window.location.protocol + '//' + host
69 }
70
71 private loadMoreFollowers () {
72 const pagination = this.restService.componentPaginationToRestPagination(this.followersPagination)
73
74 this.followService.getFollowers(pagination, this.sort)
75 .subscribe(
76 resultList => {
77 const newFollowers = resultList.data.map(r => r.follower.host)
78 this.followers = this.followers.concat(newFollowers)
79
80 this.followersPagination.totalItems = resultList.total
81 },
82
83 err => this.notifier.error(err.message)
84 )
85 }
86
87 private loadMoreFollowings () {
88 const pagination = this.restService.componentPaginationToRestPagination(this.followingsPagination)
89
90 this.followService.getFollowing(pagination, this.sort)
91 .subscribe(
92 resultList => {
93 const newFollowings = resultList.data.map(r => r.following.host)
94 this.followings = this.followings.concat(newFollowings)
95
96 this.followingsPagination.totalItems = resultList.total
97 },
98
99 err => this.notifier.error(err.message)
100 )
101 }
102
103}
diff --git a/client/src/app/+about/about-routing.module.ts b/client/src/app/+about/about-routing.module.ts
index c83c62c7f..33e5070cb 100644
--- a/client/src/app/+about/about-routing.module.ts
+++ b/client/src/app/+about/about-routing.module.ts
@@ -4,6 +4,7 @@ import { MetaGuard } from '@ngx-meta/core'
4import { AboutComponent } from './about.component' 4import { AboutComponent } from './about.component'
5import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component' 5import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component'
6import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component' 6import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component'
7import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component'
7 8
8const aboutRoutes: Routes = [ 9const aboutRoutes: Routes = [
9 { 10 {
@@ -33,6 +34,15 @@ const aboutRoutes: Routes = [
33 title: 'About PeerTube' 34 title: 'About PeerTube'
34 } 35 }
35 } 36 }
37 },
38 {
39 path: 'follows',
40 component: AboutFollowsComponent,
41 data: {
42 meta: {
43 title: 'About follows'
44 }
45 }
36 } 46 }
37 ] 47 ]
38 } 48 }
diff --git a/client/src/app/+about/about.component.html b/client/src/app/+about/about.component.html
index 8c50835c1..0c4a5156d 100644
--- a/client/src/app/+about/about.component.html
+++ b/client/src/app/+about/about.component.html
@@ -5,10 +5,12 @@
5 <a i18n routerLink="instance" routerLinkActive="active" class="title-page">Instance</a> 5 <a i18n routerLink="instance" routerLinkActive="active" class="title-page">Instance</a>
6 6
7 <a i18n routerLink="peertube" routerLinkActive="active" class="title-page">PeerTube</a> 7 <a i18n routerLink="peertube" routerLinkActive="active" class="title-page">PeerTube</a>
8
9 <a i18n routerLink="follows" routerLinkActive="active" class="title-page">Follows</a>
8 </div> 10 </div>
9 </div> 11 </div>
10 12
11 <div class="margin-content"> 13 <div class="margin-content">
12 <router-outlet></router-outlet> 14 <router-outlet></router-outlet>
13 </div> 15 </div>
14</div> \ No newline at end of file 16</div>
diff --git a/client/src/app/+about/about.module.ts b/client/src/app/+about/about.module.ts
index 9c6b29740..49a7a52f8 100644
--- a/client/src/app/+about/about.module.ts
+++ b/client/src/app/+about/about.module.ts
@@ -6,6 +6,7 @@ import { SharedModule } from '../shared'
6import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component' 6import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component'
7import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component' 7import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component'
8import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' 8import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component'
9import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component'
9 10
10@NgModule({ 11@NgModule({
11 imports: [ 12 imports: [
@@ -17,6 +18,7 @@ import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-a
17 AboutComponent, 18 AboutComponent,
18 AboutInstanceComponent, 19 AboutInstanceComponent,
19 AboutPeertubeComponent, 20 AboutPeertubeComponent,
21 AboutFollowsComponent,
20 ContactAdminModalComponent 22 ContactAdminModalComponent
21 ], 23 ],
22 24
diff --git a/client/src/app/+accounts/account-video-channels/account-video-channels.component.html b/client/src/app/+accounts/account-video-channels/account-video-channels.component.html
index c3ef1d894..43dbbebb3 100644
--- a/client/src/app/+accounts/account-video-channels/account-video-channels.component.html
+++ b/client/src/app/+accounts/account-video-channels/account-video-channels.component.html
@@ -1,11 +1,21 @@
1<div *ngIf="account" class="row"> 1<div class="margin-content">
2 <a 2
3 *ngFor="let videoChannel of videoChannels" [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" 3 <div class="no-results" i18n *ngIf="channelPagination.totalItems === 0">This account does not have channels.</div>
4 class="video-channel" i18n-title title="See this video channel" 4
5 > 5 <div class="channels" myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true">
6 <img [src]="videoChannel.avatarUrl" alt="Avatar" /> 6 <div class="section channel" *ngFor="let videoChannel of videoChannels">
7 7 <div class="section-title">
8 <div class="video-channel-display-name">{{ videoChannel.displayName }}</div> 8 <a [routerLink]="[ '/video-channels', videoChannel.nameWithHost ]" i18n-title title="See this video channel">
9 <div i18n class="video-channel-followers">{{ videoChannel.followersCount }} subscribers</div> 9 <img [src]="videoChannel.avatarUrl" alt="Avatar" />
10 </a> 10
11</div> \ No newline at end of file 11 <div>{{ videoChannel.displayName }}</div>
12 <div i18n class="followers">{{ videoChannel.followersCount }} subscribers</div>
13 </a>
14
15 <my-subscribe-button [videoChannel]="videoChannel"></my-subscribe-button>
16 </div>
17
18 <my-video-miniature *ngFor="let video of getVideosOf(videoChannel)" [video]="video" [user]="user" [displayVideoActions]="false"></my-video-miniature>
19 </div>
20 </div>
21</div>
diff --git a/client/src/app/+accounts/account-video-channels/account-video-channels.component.scss b/client/src/app/+accounts/account-video-channels/account-video-channels.component.scss
index 0c6de2efa..d9f78bdcd 100644
--- a/client/src/app/+accounts/account-video-channels/account-video-channels.component.scss
+++ b/client/src/app/+accounts/account-video-channels/account-video-channels.component.scss
@@ -1,30 +1,17 @@
1@import '_variables'; 1@import '_variables';
2@import '_mixins'; 2@import '_mixins';
3@import '_miniature';
3 4
4.row { 5.margin-content {
5 justify-content: center; 6 @include adapt-margin-content-width;
6} 7}
7 8
8a.video-channel { 9.section {
9 @include disable-default-a-behaviour; 10 @include miniature-rows;
10 11
11 display: inline-block; 12 padding-top: 0 !important;
12 text-align: center;
13 color: var(--mainForegroundColor);
14 margin: 10px 30px;
15 13
16 img { 14 .section-title {
17 @include avatar(80px); 15 align-items: center;
18
19 margin-bottom: 10px;
20 }
21
22 .video-channel-display-name {
23 font-size: 20px;
24 font-weight: $font-bold;
25 } 16 }
26 17}
27 .video-channel-followers {
28 font-size: 15px;
29 }
30} \ No newline at end of file
diff --git a/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts b/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts
index 44f5626bb..ee3b5f8e4 100644
--- a/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts
+++ b/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts
@@ -3,9 +3,14 @@ import { ActivatedRoute } from '@angular/router'
3import { Account } from '@app/shared/account/account.model' 3import { Account } from '@app/shared/account/account.model'
4import { AccountService } from '@app/shared/account/account.service' 4import { AccountService } from '@app/shared/account/account.service'
5import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' 5import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
6import { flatMap, map, tap } from 'rxjs/operators' 6import { concatMap, map, switchMap, tap } from 'rxjs/operators'
7import { Subscription } from 'rxjs' 7import { from, Subscription } from 'rxjs'
8import { VideoChannel } from '@app/shared/video-channel/video-channel.model' 8import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
9import { Video } from '@app/shared/video/video.model'
10import { AuthService } from '@app/core'
11import { VideoService } from '@app/shared/video/video.service'
12import { VideoSortField } from '@app/shared/video/sort-field.type'
13import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
9 14
10@Component({ 15@Component({
11 selector: 'my-account-video-channels', 16 selector: 'my-account-video-channels',
@@ -15,27 +20,73 @@ import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
15export class AccountVideoChannelsComponent implements OnInit, OnDestroy { 20export class AccountVideoChannelsComponent implements OnInit, OnDestroy {
16 account: Account 21 account: Account
17 videoChannels: VideoChannel[] = [] 22 videoChannels: VideoChannel[] = []
23 videos: { [id: number]: Video[] } = {}
24
25 channelPagination: ComponentPagination = {
26 currentPage: 1,
27 itemsPerPage: 2
28 }
29
30 videosPagination: ComponentPagination = {
31 currentPage: 1,
32 itemsPerPage: 12
33 }
34 videosSort: VideoSortField = '-publishedAt'
18 35
19 private accountSub: Subscription 36 private accountSub: Subscription
20 37
21 constructor ( 38 constructor (
22 protected route: ActivatedRoute, 39 private route: ActivatedRoute,
40 private authService: AuthService,
23 private accountService: AccountService, 41 private accountService: AccountService,
24 private videoChannelService: VideoChannelService 42 private videoChannelService: VideoChannelService,
43 private videoService: VideoService
25 ) { } 44 ) { }
26 45
46 get user () {
47 return this.authService.getUser()
48 }
49
27 ngOnInit () { 50 ngOnInit () {
28 // Parent get the account for us 51 // Parent get the account for us
29 this.accountSub = this.accountService.accountLoaded 52 this.accountSub = this.accountService.accountLoaded
30 .pipe( 53 .subscribe(account => {
31 tap(account => this.account = account), 54 this.account = account
32 flatMap(account => this.videoChannelService.listAccountVideoChannels(account)), 55
33 map(res => res.data) 56 this.loadMoreChannels()
34 ) 57 })
35 .subscribe(videoChannels => this.videoChannels = videoChannels)
36 } 58 }
37 59
38 ngOnDestroy () { 60 ngOnDestroy () {
39 if (this.accountSub) this.accountSub.unsubscribe() 61 if (this.accountSub) this.accountSub.unsubscribe()
40 } 62 }
63
64 loadMoreChannels () {
65 this.videoChannelService.listAccountVideoChannels(this.account, this.channelPagination)
66 .pipe(
67 tap(res => this.channelPagination.totalItems = res.total),
68 switchMap(res => from(res.data)),
69 concatMap(videoChannel => {
70 return this.videoService.getVideoChannelVideos(videoChannel, this.videosPagination, this.videosSort)
71 .pipe(map(data => ({ videoChannel, videos: data.videos })))
72 })
73 )
74 .subscribe(({ videoChannel, videos }) => {
75 this.videoChannels.push(videoChannel)
76
77 this.videos[videoChannel.id] = videos
78 })
79 }
80
81 getVideosOf (videoChannel: VideoChannel) {
82 return this.videos[ videoChannel.id ] || []
83 }
84
85 onNearOfBottom () {
86 if (!hasMoreItems(this.channelPagination)) return
87
88 this.channelPagination.currentPage += 1
89
90 this.loadMoreChannels()
91 }
41} 92}
diff --git a/client/src/app/+accounts/account-videos/account-videos.component.ts b/client/src/app/+accounts/account-videos/account-videos.component.ts
index 0d579fa0c..5a99aadce 100644
--- a/client/src/app/+accounts/account-videos/account-videos.component.ts
+++ b/client/src/app/+accounts/account-videos/account-videos.component.ts
@@ -29,6 +29,7 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
29 private accountSub: Subscription 29 private accountSub: Subscription
30 30
31 constructor ( 31 constructor (
32 protected i18n: I18n,
32 protected router: Router, 33 protected router: Router,
33 protected serverService: ServerService, 34 protected serverService: ServerService,
34 protected route: ActivatedRoute, 35 protected route: ActivatedRoute,
@@ -36,13 +37,10 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
36 protected notifier: Notifier, 37 protected notifier: Notifier,
37 protected confirmService: ConfirmService, 38 protected confirmService: ConfirmService,
38 protected screenService: ScreenService, 39 protected screenService: ScreenService,
39 private i18n: I18n,
40 private accountService: AccountService, 40 private accountService: AccountService,
41 private videoService: VideoService 41 private videoService: VideoService
42 ) { 42 ) {
43 super() 43 super()
44
45 this.titlePage = this.i18n('Published videos')
46 } 44 }
47 45
48 ngOnInit () { 46 ngOnInit () {
diff --git a/client/src/app/+accounts/accounts-routing.module.ts b/client/src/app/+accounts/accounts-routing.module.ts
index 531d763c4..55bce351a 100644
--- a/client/src/app/+accounts/accounts-routing.module.ts
+++ b/client/src/app/+accounts/accounts-routing.module.ts
@@ -14,7 +14,7 @@ const accountsRoutes: Routes = [
14 children: [ 14 children: [
15 { 15 {
16 path: '', 16 path: '',
17 redirectTo: 'videos', 17 redirectTo: 'video-channels',
18 pathMatch: 'full' 18 pathMatch: 'full'
19 }, 19 },
20 { 20 {
diff --git a/client/src/app/+accounts/accounts.component.html b/client/src/app/+accounts/accounts.component.html
index c1377c1ea..038e18c4b 100644
--- a/client/src/app/+accounts/accounts.component.html
+++ b/client/src/app/+accounts/accounts.component.html
@@ -26,10 +26,10 @@
26 </div> 26 </div>
27 27
28 <div class="links"> 28 <div class="links">
29 <a i18n routerLink="videos" routerLinkActive="active" class="title-page">Videos</a>
30
31 <a i18n routerLink="video-channels" routerLinkActive="active" class="title-page">Video channels</a> 29 <a i18n routerLink="video-channels" routerLinkActive="active" class="title-page">Video channels</a>
32 30
31 <a i18n routerLink="videos" routerLinkActive="active" class="title-page">Videos</a>
32
33 <a i18n routerLink="about" routerLinkActive="active" class="title-page">About</a> 33 <a i18n routerLink="about" routerLinkActive="active" class="title-page">About</a>
34 </div> 34 </div>
35 </div> 35 </div>
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts
index 71a4dfc4a..9ab883f60 100644
--- a/client/src/app/+admin/admin.module.ts
+++ b/client/src/app/+admin/admin.module.ts
@@ -5,7 +5,7 @@ import { TableModule } from 'primeng/table'
5import { SharedModule } from '../shared' 5import { SharedModule } from '../shared'
6import { AdminRoutingModule } from './admin-routing.module' 6import { AdminRoutingModule } from './admin-routing.module'
7import { AdminComponent } from './admin.component' 7import { AdminComponent } from './admin.component'
8import { FollowersListComponent, FollowingAddComponent, FollowsComponent, FollowService } from './follows' 8import { FollowersListComponent, FollowingAddComponent, FollowsComponent } from './follows'
9import { FollowingListComponent } from './follows/following-list/following-list.component' 9import { FollowingListComponent } from './follows/following-list/following-list.component'
10import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersComponent, UserUpdateComponent } from './users' 10import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersComponent, UserUpdateComponent } from './users'
11import { 11import {
@@ -66,7 +66,6 @@ import { DebugComponent, DebugService } from '@app/+admin/system/debug'
66 ], 66 ],
67 67
68 providers: [ 68 providers: [
69 FollowService,
70 RedundancyService, 69 RedundancyService,
71 JobService, 70 JobService,
72 LogsService, 71 LogsService,
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
index 637484622..44fc6dc26 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
+++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html
@@ -287,6 +287,14 @@
287 </div> 287 </div>
288 288
289 <div class="form-group"> 289 <div class="form-group">
290 <my-peertube-checkbox
291 inputName="transcodingAllowAudioFiles" formControlName="allowAudioFiles"
292 i18n-labelText labelText="Allow audio files upload"
293 i18n-helpHtml helpHtml="Allow your users to upload audio files that will be merged with the preview file on upload"
294 ></my-peertube-checkbox>
295 </div>
296
297 <div class="form-group">
290 <label i18n for="transcodingThreads">Transcoding threads</label> 298 <label i18n for="transcodingThreads">Transcoding threads</label>
291 <div class="peertube-select-container"> 299 <div class="peertube-select-container">
292 <select id="transcodingThreads" formControlName="threads"> 300 <select id="transcodingThreads" formControlName="threads">
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
index e64750713..c238a6c81 100644
--- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
+++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
@@ -116,6 +116,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
116 enabled: null, 116 enabled: null,
117 threads: this.customConfigValidatorsService.TRANSCODING_THREADS, 117 threads: this.customConfigValidatorsService.TRANSCODING_THREADS,
118 allowAdditionalExtensions: null, 118 allowAdditionalExtensions: null,
119 allowAudioFiles: null,
119 resolutions: {} 120 resolutions: {}
120 }, 121 },
121 autoBlacklist: { 122 autoBlacklist: {
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.ts b/client/src/app/+admin/follows/followers-list/followers-list.component.ts
index b78cdf656..e25d9ab66 100644
--- a/client/src/app/+admin/follows/followers-list/followers-list.component.ts
+++ b/client/src/app/+admin/follows/followers-list/followers-list.component.ts
@@ -3,7 +3,7 @@ import { ConfirmService, Notifier } from '@app/core'
3import { SortMeta } from 'primeng/primeng' 3import { SortMeta } from 'primeng/primeng'
4import { ActorFollow } from '../../../../../../shared/models/actors/follow.model' 4import { ActorFollow } from '../../../../../../shared/models/actors/follow.model'
5import { RestPagination, RestTable } from '../../../shared' 5import { RestPagination, RestTable } from '../../../shared'
6import { FollowService } from '../shared' 6import { FollowService } from '@app/shared/instance/follow.service'
7import { I18n } from '@ngx-translate/i18n-polyfill' 7import { I18n } from '@ngx-translate/i18n-polyfill'
8 8
9@Component({ 9@Component({
diff --git a/client/src/app/+admin/follows/following-add/following-add.component.ts b/client/src/app/+admin/follows/following-add/following-add.component.ts
index 2bb249746..308bbb0c5 100644
--- a/client/src/app/+admin/follows/following-add/following-add.component.ts
+++ b/client/src/app/+admin/follows/following-add/following-add.component.ts
@@ -3,7 +3,7 @@ import { Router } from '@angular/router'
3import { Notifier } from '@app/core' 3import { Notifier } from '@app/core'
4import { ConfirmService } from '../../../core' 4import { ConfirmService } from '../../../core'
5import { validateHost } from '../../../shared' 5import { validateHost } from '../../../shared'
6import { FollowService } from '../shared' 6import { FollowService } from '@app/shared/instance/follow.service'
7import { I18n } from '@ngx-translate/i18n-polyfill' 7import { I18n } from '@ngx-translate/i18n-polyfill'
8 8
9@Component({ 9@Component({
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.ts b/client/src/app/+admin/follows/following-list/following-list.component.ts
index 4517a721e..ded616624 100644
--- a/client/src/app/+admin/follows/following-list/following-list.component.ts
+++ b/client/src/app/+admin/follows/following-list/following-list.component.ts
@@ -4,7 +4,7 @@ import { SortMeta } from 'primeng/primeng'
4import { ActorFollow } from '../../../../../../shared/models/actors/follow.model' 4import { ActorFollow } from '../../../../../../shared/models/actors/follow.model'
5import { ConfirmService } from '../../../core/confirm/confirm.service' 5import { ConfirmService } from '../../../core/confirm/confirm.service'
6import { RestPagination, RestTable } from '../../../shared' 6import { RestPagination, RestTable } from '../../../shared'
7import { FollowService } from '../shared' 7import { FollowService } from '@app/shared/instance/follow.service'
8import { I18n } from '@ngx-translate/i18n-polyfill' 8import { I18n } from '@ngx-translate/i18n-polyfill'
9 9
10@Component({ 10@Component({
diff --git a/client/src/app/+admin/follows/index.ts b/client/src/app/+admin/follows/index.ts
index 7849a06e7..e94f33710 100644
--- a/client/src/app/+admin/follows/index.ts
+++ b/client/src/app/+admin/follows/index.ts
@@ -1,6 +1,5 @@
1export * from './following-add' 1export * from './following-add'
2export * from './followers-list' 2export * from './followers-list'
3export * from './following-list' 3export * from './following-list'
4export * from './shared'
5export * from './follows.component' 4export * from './follows.component'
6export * from './follows.routes' 5export * from './follows.routes'
diff --git a/client/src/app/+admin/follows/shared/index.ts b/client/src/app/+admin/follows/shared/index.ts
deleted file mode 100644
index 78d456def..000000000
--- a/client/src/app/+admin/follows/shared/index.ts
+++ /dev/null
@@ -1 +0,0 @@
1export * from './follow.service'
diff --git a/client/src/app/+admin/users/user-edit/user-edit.ts b/client/src/app/+admin/users/user-edit/user-edit.ts
index adce1b2d4..ee6d2c489 100644
--- a/client/src/app/+admin/users/user-edit/user-edit.ts
+++ b/client/src/app/+admin/users/user-edit/user-edit.ts
@@ -7,7 +7,8 @@ import { UserAdminFlag } from '@shared/models/users/user-flag.model'
7export abstract class UserEdit extends FormReactive { 7export abstract class UserEdit extends FormReactive {
8 videoQuotaOptions: { value: string, label: string }[] = [] 8 videoQuotaOptions: { value: string, label: string }[] = []
9 videoQuotaDailyOptions: { value: string, label: string }[] = [] 9 videoQuotaDailyOptions: { value: string, label: string }[] = []
10 roles = Object.keys(USER_ROLE_LABELS).map(key => ({ value: key.toString(), label: USER_ROLE_LABELS[key] })) 10 roles = Object.keys(USER_ROLE_LABELS)
11 .map(key => ({ value: key.toString(), label: USER_ROLE_LABELS[key] }))
11 username: string 12 username: string
12 userId: number 13 userId: number
13 14
@@ -27,7 +28,7 @@ export abstract class UserEdit extends FormReactive {
27 const transcodingConfig = this.serverService.getConfig().transcoding 28 const transcodingConfig = this.serverService.getConfig().transcoding
28 29
29 const resolutions = transcodingConfig.enabledResolutions 30 const resolutions = transcodingConfig.enabledResolutions
30 const higherResolution = VideoResolution.H_1080P 31 const higherResolution = VideoResolution.H_4K
31 let multiplier = 0 32 let multiplier = 0
32 33
33 for (const resolution of resolutions) { 34 for (const resolution of resolutions) {
diff --git a/client/src/app/+my-account/my-account-history/my-account-history.component.ts b/client/src/app/+my-account/my-account-history/my-account-history.component.ts
index 73340d21a..13607119e 100644
--- a/client/src/app/+my-account/my-account-history/my-account-history.component.ts
+++ b/client/src/app/+my-account/my-account-history/my-account-history.component.ts
@@ -27,6 +27,7 @@ export class MyAccountHistoryComponent extends AbstractVideoList implements OnIn
27 videosHistoryEnabled: boolean 27 videosHistoryEnabled: boolean
28 28
29 constructor ( 29 constructor (
30 protected i18n: I18n,
30 protected router: Router, 31 protected router: Router,
31 protected serverService: ServerService, 32 protected serverService: ServerService,
32 protected route: ActivatedRoute, 33 protected route: ActivatedRoute,
@@ -34,7 +35,6 @@ export class MyAccountHistoryComponent extends AbstractVideoList implements OnIn
34 protected userService: UserService, 35 protected userService: UserService,
35 protected notifier: Notifier, 36 protected notifier: Notifier,
36 protected screenService: ScreenService, 37 protected screenService: ScreenService,
37 protected i18n: I18n,
38 private confirmService: ConfirmService, 38 private confirmService: ConfirmService,
39 private videoService: VideoService, 39 private videoService: VideoService,
40 private userHistoryService: UserHistoryService 40 private userHistoryService: UserHistoryService
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html
index 81fb11f45..f87df87df 100644
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html
+++ b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.component.html
@@ -61,5 +61,12 @@ When you will upload a video in this channel, the video support field will be au
61 </div> 61 </div>
62 </div> 62 </div>
63 63
64 <div class="form-group" *ngIf="isBulkUpdateVideosDisplayed()">
65 <my-peertube-checkbox
66 inputName="bulkVideosSupportUpdate" formControlName="bulkVideosSupportUpdate"
67 i18n-labelText labelText="Overwrite support field of all videos of this channel"
68 ></my-peertube-checkbox>
69 </div>
70
64 <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid"> 71 <input type="submit" value="{{ getFormButtonTitle() }}" [disabled]="!form.valid">
65</form> 72</form>
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts
index 4dc65dd99..7479442d1 100644
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts
+++ b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts
@@ -11,4 +11,9 @@ export abstract class MyAccountVideoChannelEdit extends FormReactive {
11 11
12 // FIXME: We need this method so angular does not complain in the child template 12 // FIXME: We need this method so angular does not complain in the child template
13 onAvatarChange (formData: FormData) { /* empty */ } 13 onAvatarChange (formData: FormData) { /* empty */ }
14
15 // Should be implemented by the child
16 isBulkUpdateVideosDisplayed () {
17 return false
18 }
14} 19}
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts
index da4fb645a..081e956d2 100644
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts
+++ b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-update.component.ts
@@ -20,6 +20,7 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
20 videoChannelToUpdate: VideoChannel 20 videoChannelToUpdate: VideoChannel
21 21
22 private paramsSub: Subscription 22 private paramsSub: Subscription
23 private oldSupportField: string
23 24
24 constructor ( 25 constructor (
25 protected formValidatorService: FormValidatorService, 26 protected formValidatorService: FormValidatorService,
@@ -39,7 +40,8 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
39 this.buildForm({ 40 this.buildForm({
40 'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME, 41 'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME,
41 description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION, 42 description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION,
42 support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT 43 support: this.videoChannelValidatorsService.VIDEO_CHANNEL_SUPPORT,
44 bulkVideosSupportUpdate: null
43 }) 45 })
44 46
45 this.paramsSub = this.route.params.subscribe(routeParams => { 47 this.paramsSub = this.route.params.subscribe(routeParams => {
@@ -49,6 +51,8 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
49 videoChannelToUpdate => { 51 videoChannelToUpdate => {
50 this.videoChannelToUpdate = videoChannelToUpdate 52 this.videoChannelToUpdate = videoChannelToUpdate
51 53
54 this.oldSupportField = videoChannelToUpdate.support
55
52 this.form.patchValue({ 56 this.form.patchValue({
53 'display-name': videoChannelToUpdate.displayName, 57 'display-name': videoChannelToUpdate.displayName,
54 description: videoChannelToUpdate.description, 58 description: videoChannelToUpdate.description,
@@ -72,7 +76,8 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
72 const videoChannelUpdate: VideoChannelUpdate = { 76 const videoChannelUpdate: VideoChannelUpdate = {
73 displayName: body['display-name'], 77 displayName: body['display-name'],
74 description: body.description || null, 78 description: body.description || null,
75 support: body.support || null 79 support: body.support || null,
80 bulkVideosSupportUpdate: body.bulkVideosSupportUpdate || false
76 } 81 }
77 82
78 this.videoChannelService.updateVideoChannel(this.videoChannelToUpdate.name, videoChannelUpdate).subscribe( 83 this.videoChannelService.updateVideoChannel(this.videoChannelToUpdate.name, videoChannelUpdate).subscribe(
@@ -118,4 +123,10 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
118 getFormButtonTitle () { 123 getFormButtonTitle () {
119 return this.i18n('Update') 124 return this.i18n('Update')
120 } 125 }
126
127 isBulkUpdateVideosDisplayed () {
128 if (this.oldSupportField === undefined) return false
129
130 return this.oldSupportField !== this.form.value['support']
131 }
121} 132}
diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-create.component.ts b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-create.component.ts
index 87a10961f..8aed8b513 100644
--- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-create.component.ts
+++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-create.component.ts
@@ -7,7 +7,6 @@ import { FormValidatorService } from '@app/shared/forms/form-validators/form-val
7import { VideoPlaylistValidatorsService } from '@app/shared' 7import { VideoPlaylistValidatorsService } from '@app/shared'
8import { VideoPlaylistCreate } from '@shared/models/videos/playlist/video-playlist-create.model' 8import { VideoPlaylistCreate } from '@shared/models/videos/playlist/video-playlist-create.model'
9import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' 9import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
10import { VideoConstant } from '@shared/models'
11import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model' 10import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model'
12import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils' 11import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils'
13 12
@@ -18,7 +17,6 @@ import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils'
18}) 17})
19export class MyAccountVideoPlaylistCreateComponent extends MyAccountVideoPlaylistEdit implements OnInit { 18export class MyAccountVideoPlaylistCreateComponent extends MyAccountVideoPlaylistEdit implements OnInit {
20 error: string 19 error: string
21 videoPlaylistPrivacies: VideoConstant<VideoPlaylistPrivacy>[] = []
22 20
23 constructor ( 21 constructor (
24 protected formValidatorService: FormValidatorService, 22 protected formValidatorService: FormValidatorService,
@@ -47,6 +45,7 @@ export class MyAccountVideoPlaylistCreateComponent extends MyAccountVideoPlaylis
47 }) 45 })
48 46
49 populateAsyncUserVideoChannels(this.authService, this.userVideoChannels) 47 populateAsyncUserVideoChannels(this.authService, this.userVideoChannels)
48 .catch(err => console.error('Cannot populate user video channels.', err))
50 49
51 this.serverService.videoPlaylistPrivaciesLoaded.subscribe( 50 this.serverService.videoPlaylistPrivaciesLoaded.subscribe(
52 () => { 51 () => {
diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.component.html b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.component.html
index 303fc46f7..82321459f 100644
--- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.component.html
+++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.component.html
@@ -57,10 +57,12 @@
57 </div> 57 </div>
58 58
59 <div class="form-group"> 59 <div class="form-group">
60 <my-image-upload 60 <label i18n>Playlist thumbnail</label>
61 i18n-inputLabel inputLabel="Upload thumbnail" inputName="thumbnailfile" formControlName="thumbnailfile" 61
62 previewWidth="200px" previewHeight="110px" 62 <my-preview-upload
63 ></my-image-upload> 63 i18n-inputLabel inputLabel="Edit" inputName="thumbnailfile" formControlName="thumbnailfile"
64 previewWidth="223px" previewHeight="122px"
65 ></my-preview-upload>
64 </div> 66 </div>
65 </div> 67 </div>
66 </div> 68 </div>
diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.ts b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.ts
index fbfb4c8f7..e94188786 100644
--- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.ts
+++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-edit.ts
@@ -1,12 +1,12 @@
1import { FormReactive } from '@app/shared' 1import { FormReactive } from '@app/shared'
2import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
3import { ServerService } from '@app/core'
4import { VideoPlaylist } from '@shared/models/videos/playlist/video-playlist.model' 2import { VideoPlaylist } from '@shared/models/videos/playlist/video-playlist.model'
3import { VideoConstant, VideoPlaylistPrivacy } from '@shared/models'
5 4
6export abstract class MyAccountVideoPlaylistEdit extends FormReactive { 5export abstract class MyAccountVideoPlaylistEdit extends FormReactive {
7 // Declare it here to avoid errors in create template 6 // Declare it here to avoid errors in create template
8 videoPlaylistToUpdate: VideoPlaylist 7 videoPlaylistToUpdate: VideoPlaylist
9 userVideoChannels: { id: number, label: string }[] = [] 8 userVideoChannels: { id: number, label: string }[] = []
9 videoPlaylistPrivacies: VideoConstant<VideoPlaylistPrivacy>[] = []
10 10
11 abstract isCreation (): boolean 11 abstract isCreation (): boolean
12 abstract getFormButtonTitle (): string 12 abstract getFormButtonTitle (): string
diff --git a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-update.component.ts b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-update.component.ts
index 4887fdfb4..917ad7258 100644
--- a/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-update.component.ts
+++ b/client/src/app/+my-account/my-account-video-playlists/my-account-video-playlist-update.component.ts
@@ -9,9 +9,8 @@ import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils'
9import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' 9import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
10import { VideoPlaylistValidatorsService } from '@app/shared' 10import { VideoPlaylistValidatorsService } from '@app/shared'
11import { VideoPlaylistUpdate } from '@shared/models/videos/playlist/video-playlist-update.model' 11import { VideoPlaylistUpdate } from '@shared/models/videos/playlist/video-playlist-update.model'
12import { VideoConstant } from '@shared/models'
13import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model'
14import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' 12import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
13import { delayWhen, map, switchMap } from 'rxjs/operators'
15 14
16@Component({ 15@Component({
17 selector: 'my-account-video-playlist-update', 16 selector: 'my-account-video-playlist-update',
@@ -21,7 +20,6 @@ import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
21export class MyAccountVideoPlaylistUpdateComponent extends MyAccountVideoPlaylistEdit implements OnInit, OnDestroy { 20export class MyAccountVideoPlaylistUpdateComponent extends MyAccountVideoPlaylistEdit implements OnInit, OnDestroy {
22 error: string 21 error: string
23 videoPlaylistToUpdate: VideoPlaylist 22 videoPlaylistToUpdate: VideoPlaylist
24 videoPlaylistPrivacies: VideoConstant<VideoPlaylistPrivacy>[] = []
25 23
26 private paramsSub: Subscription 24 private paramsSub: Subscription
27 25
@@ -53,31 +51,24 @@ export class MyAccountVideoPlaylistUpdateComponent extends MyAccountVideoPlaylis
53 }) 51 })
54 52
55 populateAsyncUserVideoChannels(this.authService, this.userVideoChannels) 53 populateAsyncUserVideoChannels(this.authService, this.userVideoChannels)
56 54 .catch(err => console.error('Cannot populate user video channels.', err))
57 this.paramsSub = this.route.params.subscribe(routeParams => { 55
58 const videoPlaylistId = routeParams['videoPlaylistId'] 56 this.paramsSub = this.route.params
59 57 .pipe(
60 this.videoPlaylistService.getVideoPlaylist(videoPlaylistId).subscribe( 58 map(routeParams => routeParams['videoPlaylistId']),
61 videoPlaylistToUpdate => { 59 switchMap(videoPlaylistId => this.videoPlaylistService.getVideoPlaylist(videoPlaylistId)),
62 this.videoPlaylistToUpdate = videoPlaylistToUpdate 60 delayWhen(() => this.serverService.videoPlaylistPrivaciesLoaded)
63 61 )
64 this.hydrateFormFromPlaylist() 62 .subscribe(
65 63 videoPlaylistToUpdate => {
66 this.serverService.videoPlaylistPrivaciesLoaded.subscribe( 64 this.videoPlaylistPrivacies = this.serverService.getVideoPlaylistPrivacies()
67 () => { 65 this.videoPlaylistToUpdate = videoPlaylistToUpdate
68 this.videoPlaylistPrivacies = this.serverService.getVideoPlaylistPrivacies() 66
69 .filter(p => { 67 this.hydrateFormFromPlaylist()
70 // If the playlist is not private, we cannot put it in private anymore 68 },
71 return this.videoPlaylistToUpdate.privacy.id === VideoPlaylistPrivacy.PRIVATE || 69
72 p.id !== VideoPlaylistPrivacy.PRIVATE 70 err => this.error = err.message
73 }) 71 )
74 }
75 )
76 },
77
78 err => this.error = err.message
79 )
80 })
81 } 72 }
82 73
83 ngOnDestroy () { 74 ngOnDestroy () {
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
index 84d464800..2854093c4 100644
--- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
+++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
@@ -20,7 +20,7 @@
20 <my-edit-button [routerLink]="[ '/videos', 'update', video.uuid ]"></my-edit-button> 20 <my-edit-button [routerLink]="[ '/videos', 'update', video.uuid ]"></my-edit-button>
21 21
22 <my-button i18n-label label="Change ownership" 22 <my-button i18n-label label="Change ownership"
23 className="action-button-change-ownership" 23 className="action-button-change-ownership grey-button"
24 icon="im-with-her" 24 icon="im-with-her"
25 (click)="changeOwnership($event, video)" 25 (click)="changeOwnership($event, video)"
26 ></my-button> 26 ></my-button>
diff --git a/client/src/app/+signup/+register/custom-stepper.component.html b/client/src/app/+signup/+register/custom-stepper.component.html
new file mode 100644
index 000000000..bf507fc4f
--- /dev/null
+++ b/client/src/app/+signup/+register/custom-stepper.component.html
@@ -0,0 +1,25 @@
1<section class="container">
2 <header>
3 <ng-container *ngFor="let step of steps; let i = index; let isLast = last;">
4 <div
5 class="step-info" [ngClass]="{ active: selectedIndex === i, completed: isCompleted(step) }"
6 (click)="onClick(i)"
7 >
8 <div class="step-index">
9 <ng-container *ngIf="!isCompleted(step)">{{ i + 1 }}</ng-container>
10 <my-global-icon *ngIf="isCompleted(step)" iconName="tick"></my-global-icon>
11 </div>
12
13 <div class="step-label">{{ step.label }}</div>
14 </div>
15
16 <!-- Do no display if this is the last child -->
17 <div *ngIf="!isLast" class="connector"></div>
18 </ng-container>
19 </header>
20
21 <div [style.display]="selected ? 'block' : 'none'">
22 <ng-container [ngTemplateOutlet]="selected.content"></ng-container>
23 </div>
24
25</section>
diff --git a/client/src/app/+signup/+register/custom-stepper.component.scss b/client/src/app/+signup/+register/custom-stepper.component.scss
new file mode 100644
index 000000000..2371c8ae5
--- /dev/null
+++ b/client/src/app/+signup/+register/custom-stepper.component.scss
@@ -0,0 +1,66 @@
1@import '_variables';
2@import '_mixins';
3
4$grey-color: #9CA3AB;
5$index-block-height: 32px;
6
7header {
8 display: flex;
9 justify-content: space-between;
10 font-size: 15px;
11 margin-bottom: 30px;
12
13 .step-info {
14 color: $grey-color;
15 display: flex;
16 flex-direction: column;
17 align-items: center;
18 width: $index-block-height;
19
20 .step-index {
21 display: flex;
22 justify-content: center;
23 align-items: center;
24 width: $index-block-height;
25 height: $index-block-height;
26 border-radius: 100px;
27 border: 2px solid $grey-color;
28 margin-bottom: 10px;
29
30 my-global-icon {
31 @include apply-svg-color(var(--mainBackgroundColor));
32
33 width: 22px;
34 height: 22px;
35 }
36 }
37
38 .step-label {
39 width: max-content;
40 }
41
42 &.active,
43 &.completed {
44 .step-index {
45 border-color: var(--mainColor);
46 background-color: var(--mainColor);
47 color: var(--mainBackgroundColor);
48 }
49
50 .step-label {
51 color: var(--mainColor);
52 }
53 }
54
55 &.completed {
56 cursor: pointer;
57 }
58 }
59
60 .connector {
61 flex: auto;
62 margin: $index-block-height/2 10px 0 10px;
63 height: 2px;
64 background-color: $grey-color;
65 }
66}
diff --git a/client/src/app/+signup/+register/custom-stepper.component.ts b/client/src/app/+signup/+register/custom-stepper.component.ts
new file mode 100644
index 000000000..2ae40f3a9
--- /dev/null
+++ b/client/src/app/+signup/+register/custom-stepper.component.ts
@@ -0,0 +1,19 @@
1import { Component } from '@angular/core'
2import { CdkStep, CdkStepper } from '@angular/cdk/stepper'
3
4@Component({
5 selector: 'my-custom-stepper',
6 templateUrl: './custom-stepper.component.html',
7 styleUrls: [ './custom-stepper.component.scss' ],
8 providers: [ { provide: CdkStepper, useExisting: CustomStepperComponent } ]
9})
10export class CustomStepperComponent extends CdkStepper {
11
12 onClick (index: number): void {
13 this.selectedIndex = index
14 }
15
16 isCompleted (step: CdkStep) {
17 return step.stepControl && step.stepControl.dirty && step.stepControl.valid
18 }
19}
diff --git a/client/src/app/signup/signup-routing.module.ts b/client/src/app/+signup/+register/register-routing.module.ts
index 820d16d4d..e3a5001dc 100644
--- a/client/src/app/signup/signup-routing.module.ts
+++ b/client/src/app/+signup/+register/register-routing.module.ts
@@ -1,17 +1,18 @@
1import { NgModule } from '@angular/core' 1import { NgModule } from '@angular/core'
2import { RouterModule, Routes } from '@angular/router' 2import { RouterModule, Routes } from '@angular/router'
3import { MetaGuard } from '@ngx-meta/core' 3import { MetaGuard } from '@ngx-meta/core'
4import { SignupComponent } from './signup.component' 4import { RegisterComponent } from './register.component'
5import { ServerConfigResolver } from '@app/core/routing/server-config-resolver.service' 5import { ServerConfigResolver } from '@app/core/routing/server-config-resolver.service'
6import { UnloggedGuard } from '@app/core/routing/unlogged-guard.service'
6 7
7const signupRoutes: Routes = [ 8const registerRoutes: Routes = [
8 { 9 {
9 path: 'signup', 10 path: '',
10 component: SignupComponent, 11 component: RegisterComponent,
11 canActivate: [ MetaGuard ], 12 canActivate: [ MetaGuard, UnloggedGuard ],
12 data: { 13 data: {
13 meta: { 14 meta: {
14 title: 'Signup' 15 title: 'Register'
15 } 16 }
16 }, 17 },
17 resolve: { 18 resolve: {
@@ -21,7 +22,7 @@ const signupRoutes: Routes = [
21] 22]
22 23
23@NgModule({ 24@NgModule({
24 imports: [ RouterModule.forChild(signupRoutes) ], 25 imports: [ RouterModule.forChild(registerRoutes) ],
25 exports: [ RouterModule ] 26 exports: [ RouterModule ]
26}) 27})
27export class SignupRoutingModule {} 28export class RegisterRoutingModule {}
diff --git a/client/src/app/+signup/+register/register-step-channel.component.html b/client/src/app/+signup/+register/register-step-channel.component.html
new file mode 100644
index 000000000..68ea4473a
--- /dev/null
+++ b/client/src/app/+signup/+register/register-step-channel.component.html
@@ -0,0 +1,50 @@
1<form role="form" [formGroup]="form">
2
3 <div class="channel-explanations">
4 <p i18n>
5 A channel is an entity in which you upload your videos. Creating several of them helps you to organize and separate your content.<br />
6 For example, you could decide to have a channel to publish your piano concerts, and another channel in which you publish your videos talking about ecology.
7 </p>
8
9 <p>
10 Other users can decide to subscribe any channel they want, to be notified when you publish a new video.
11 </p>
12 </div>
13
14 <div class="form-group">
15 <label for="name" i18n>Channel name</label>
16
17 <div class="input-group">
18 <input
19 type="text" id="name" i18n-placeholder placeholder="Example: my_super_channel"
20 formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }"
21 >
22 <div class="input-group-append">
23 <span class="input-group-text">@{{ instanceHost }}</span>
24 </div>
25 </div>
26
27 <div *ngIf="formErrors.name" class="form-error">
28 {{ formErrors.name }}
29 </div>
30
31 <div *ngIf="isSameThanUsername()" class="form-error" i18n>
32 Channel name cannot be the same than your account name. You can click on the first step to update your account name.
33 </div>
34 </div>
35
36 <div class="form-group">
37 <label for="displayName" i18n>Channel display name</label>
38
39 <div class="input-group">
40 <input
41 type="text" id="displayName"
42 formControlName="displayName" [ngClass]="{ 'input-error': formErrors['displayName'] }"
43 >
44 </div>
45
46 <div *ngIf="formErrors.displayName" class="form-error">
47 {{ formErrors.displayName }}
48 </div>
49 </div>
50</form>
diff --git a/client/src/app/+signup/+register/register-step-channel.component.ts b/client/src/app/+signup/+register/register-step-channel.component.ts
new file mode 100644
index 000000000..9e13f75b3
--- /dev/null
+++ b/client/src/app/+signup/+register/register-step-channel.component.ts
@@ -0,0 +1,40 @@
1import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
2import { AuthService } from '@app/core'
3import { FormReactive, VideoChannelValidatorsService } from '@app/shared'
4import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
5import { FormGroup } from '@angular/forms'
6
7@Component({
8 selector: 'my-register-step-channel',
9 templateUrl: './register-step-channel.component.html',
10 styleUrls: [ './register.component.scss' ]
11})
12export class RegisterStepChannelComponent extends FormReactive implements OnInit {
13 @Input() username: string
14 @Output() formBuilt = new EventEmitter<FormGroup>()
15
16 constructor (
17 protected formValidatorService: FormValidatorService,
18 private authService: AuthService,
19 private videoChannelValidatorsService: VideoChannelValidatorsService
20 ) {
21 super()
22 }
23
24 get instanceHost () {
25 return window.location.host
26 }
27
28 isSameThanUsername () {
29 return this.username && this.username === this.form.value['name']
30 }
31
32 ngOnInit () {
33 this.buildForm({
34 name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME,
35 displayName: this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME
36 })
37
38 setTimeout(() => this.formBuilt.emit(this.form))
39 }
40}
diff --git a/client/src/app/+signup/+register/register-step-user.component.html b/client/src/app/+signup/+register/register-step-user.component.html
new file mode 100644
index 000000000..cd0c78bfa
--- /dev/null
+++ b/client/src/app/+signup/+register/register-step-user.component.html
@@ -0,0 +1,54 @@
1<form role="form" [formGroup]="form">
2
3 <div class="form-group">
4 <label for="username" i18n>Username</label>
5
6 <div class="input-group">
7 <input
8 type="text" id="username" i18n-placeholder placeholder="Example: jane_doe"
9 formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
10 >
11 <div class="input-group-append">
12 <span class="input-group-text">@{{ instanceHost }}</span>
13 </div>
14 </div>
15
16 <div *ngIf="formErrors.username" class="form-error">
17 {{ formErrors.username }}
18 </div>
19 </div>
20
21 <div class="form-group">
22 <label for="email" i18n>Email</label>
23 <input
24 type="text" id="email" i18n-placeholder placeholder="Email"
25 formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }"
26 >
27 <div *ngIf="formErrors.email" class="form-error">
28 {{ formErrors.email }}
29 </div>
30 </div>
31
32 <div class="form-group">
33 <label for="password" i18n>Password</label>
34 <input
35 type="password" id="password" i18n-placeholder placeholder="Password"
36 formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
37 >
38 <div *ngIf="formErrors.password" class="form-error">
39 {{ formErrors.password }}
40 </div>
41 </div>
42
43 <div class="form-group form-group-terms">
44 <my-peertube-checkbox
45 inputName="terms" formControlName="terms"
46 i18n-labelHtml
47 labelHtml="I am at least 16 years old and agree to the <a href='/about/instance#terms-section' target='_blank'rel='noopener noreferrer'>Terms</a> of this instance"
48 ></my-peertube-checkbox>
49
50 <div *ngIf="formErrors.terms" class="form-error">
51 {{ formErrors.terms }}
52 </div>
53 </div>
54</form>
diff --git a/client/src/app/+signup/+register/register-step-user.component.ts b/client/src/app/+signup/+register/register-step-user.component.ts
new file mode 100644
index 000000000..3825ae371
--- /dev/null
+++ b/client/src/app/+signup/+register/register-step-user.component.ts
@@ -0,0 +1,37 @@
1import { Component, EventEmitter, OnInit, Output } from '@angular/core'
2import { AuthService } from '@app/core'
3import { FormReactive, UserValidatorsService } from '@app/shared'
4import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
5import { FormGroup } from '@angular/forms'
6
7@Component({
8 selector: 'my-register-step-user',
9 templateUrl: './register-step-user.component.html',
10 styleUrls: [ './register.component.scss' ]
11})
12export class RegisterStepUserComponent extends FormReactive implements OnInit {
13 @Output() formBuilt = new EventEmitter<FormGroup>()
14
15 constructor (
16 protected formValidatorService: FormValidatorService,
17 private authService: AuthService,
18 private userValidatorsService: UserValidatorsService
19 ) {
20 super()
21 }
22
23 get instanceHost () {
24 return window.location.host
25 }
26
27 ngOnInit () {
28 this.buildForm({
29 username: this.userValidatorsService.USER_USERNAME,
30 password: this.userValidatorsService.USER_PASSWORD,
31 email: this.userValidatorsService.USER_EMAIL,
32 terms: this.userValidatorsService.USER_TERMS
33 })
34
35 setTimeout(() => this.formBuilt.emit(this.form))
36 }
37}
diff --git a/client/src/app/+signup/+register/register.component.html b/client/src/app/+signup/+register/register.component.html
new file mode 100644
index 000000000..24def68c1
--- /dev/null
+++ b/client/src/app/+signup/+register/register.component.html
@@ -0,0 +1,41 @@
1<div class="margin-content">
2
3 <div i18n class="title-page title-page-single">
4 Create an account
5 </div>
6
7 <my-signup-success *ngIf="signupDone" [message]="success"></my-signup-success>
8 <div *ngIf="info" class="alert alert-info">{{ info }}</div>
9
10 <div class="wrapper" *ngIf="!signupDone">
11 <div>
12 <my-custom-stepper linear *ngIf="!signupDone">
13 <cdk-step [stepControl]="formStepUser" i18n-label label="User information">
14 <my-register-step-user (formBuilt)="onUserFormBuilt($event)"></my-register-step-user>
15
16 <button i18n cdkStepperNext [disabled]="!formStepUser || !formStepUser.valid">Next</button>
17 </cdk-step>
18
19 <cdk-step [stepControl]="formStepChannel" i18n-label label="Channel information">
20 <my-register-step-channel (formBuilt)="onChannelFormBuilt($event)" [username]="getUsername()"></my-register-step-channel>
21
22 <button i18n cdkStepperNext (click)="signup()"
23 [disabled]="!formStepChannel || !formStepChannel.valid || hasSameChannelAndAccountNames()"
24 >
25 Create my account
26 </button>
27 </cdk-step>
28
29 <cdk-step i18n-label label="Done" editable="false">
30 <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
31 </cdk-step>
32 </my-custom-stepper>
33 </div>
34
35 <div>
36 <label i18n>Features found on this instance</label>
37 <my-instance-features-table></my-instance-features-table>
38 </div>
39 </div>
40
41</div>
diff --git a/client/src/app/signup/signup.component.scss b/client/src/app/+signup/+register/register.component.scss
index 90e1e8e74..6f61b78f7 100644
--- a/client/src/app/signup/signup.component.scss
+++ b/client/src/app/+signup/+register/register.component.scss
@@ -1,16 +1,32 @@
1@import '_variables'; 1@import '_variables';
2@import '_mixins'; 2@import '_mixins';
3 3
4.alert {
5 font-size: 15px;
6 text-align: center;
7}
8
9.wrapper {
10 display: flex;
11 justify-content: space-between;
12 flex-wrap: wrap;
13
14 & > div {
15 margin-bottom: 40px;
16 width: 450px;
17
18 @media screen and (max-width: 500px) {
19 width: auto;
20 }
21 }
22}
23
4my-instance-features-table { 24my-instance-features-table {
5 display: block; 25 display: block;
6 26
7 margin-bottom: 40px; 27 margin-bottom: 40px;
8} 28}
9 29
10form {
11 margin: 0 60px 40px 0;
12}
13
14.form-group-terms { 30.form-group-terms {
15 margin: 30px 0; 31 margin: 30px 0;
16} 32}
@@ -25,15 +41,18 @@ form {
25 41
26input:not([type=submit]) { 42input:not([type=submit]) {
27 @include peertube-input-text(400px); 43 @include peertube-input-text(400px);
44
28 display: block; 45 display: block;
29 46
30 &#username { 47 &#username,
31 width: auto; 48 &#name {
49 width: auto !important;
32 flex-grow: 1; 50 flex-grow: 1;
33 } 51 }
34} 52}
35 53
36input[type=submit] { 54input[type=submit],
55button {
37 @include peertube-button; 56 @include peertube-button;
38 @include orange-button; 57 @include orange-button;
39} 58}
diff --git a/client/src/app/+signup/+register/register.component.ts b/client/src/app/+signup/+register/register.component.ts
new file mode 100644
index 000000000..cd6059728
--- /dev/null
+++ b/client/src/app/+signup/+register/register.component.ts
@@ -0,0 +1,89 @@
1import { Component } from '@angular/core'
2import { AuthService, Notifier, RedirectService, ServerService } from '@app/core'
3import { UserService, UserValidatorsService } from '@app/shared'
4import { I18n } from '@ngx-translate/i18n-polyfill'
5import { UserRegister } from '@shared/models/users/user-register.model'
6import { FormGroup } from '@angular/forms'
7
8@Component({
9 selector: 'my-register',
10 templateUrl: './register.component.html',
11 styleUrls: [ './register.component.scss' ]
12})
13export class RegisterComponent {
14 info: string = null
15 error: string = null
16 success: string = null
17 signupDone = false
18
19 formStepUser: FormGroup
20 formStepChannel: FormGroup
21
22 constructor (
23 private authService: AuthService,
24 private userValidatorsService: UserValidatorsService,
25 private notifier: Notifier,
26 private userService: UserService,
27 private serverService: ServerService,
28 private redirectService: RedirectService,
29 private i18n: I18n
30 ) {
31 }
32
33 get requiresEmailVerification () {
34 return this.serverService.getConfig().signup.requiresEmailVerification
35 }
36
37 hasSameChannelAndAccountNames () {
38 return this.getUsername() === this.getChannelName()
39 }
40
41 getUsername () {
42 if (!this.formStepUser) return undefined
43
44 return this.formStepUser.value['username']
45 }
46
47 getChannelName () {
48 if (!this.formStepChannel) return undefined
49
50 return this.formStepChannel.value['name']
51 }
52
53 onUserFormBuilt (form: FormGroup) {
54 this.formStepUser = form
55 }
56
57 onChannelFormBuilt (form: FormGroup) {
58 this.formStepChannel = form
59 }
60
61 signup () {
62 this.error = null
63
64 const body: UserRegister = Object.assign(this.formStepUser.value, { channel: this.formStepChannel.value })
65
66 this.userService.signup(body).subscribe(
67 () => {
68 this.signupDone = true
69
70 if (this.requiresEmailVerification) {
71 this.info = this.i18n('Now please check your emails to verify your account and complete signup.')
72 return
73 }
74
75 // Auto login
76 this.authService.login(body.username, body.password)
77 .subscribe(
78 () => {
79 this.success = this.i18n('You are now logged in as {{username}}!', { username: body.username })
80 },
81
82 err => this.error = err.message
83 )
84 },
85
86 err => this.error = err.message
87 )
88 }
89}
diff --git a/client/src/app/+signup/+register/register.module.ts b/client/src/app/+signup/+register/register.module.ts
new file mode 100644
index 000000000..46336cbd0
--- /dev/null
+++ b/client/src/app/+signup/+register/register.module.ts
@@ -0,0 +1,33 @@
1import { NgModule } from '@angular/core'
2import { RegisterRoutingModule } from './register-routing.module'
3import { RegisterComponent } from './register.component'
4import { SharedModule } from '@app/shared'
5import { CdkStepperModule } from '@angular/cdk/stepper'
6import { RegisterStepChannelComponent } from './register-step-channel.component'
7import { RegisterStepUserComponent } from './register-step-user.component'
8import { CustomStepperComponent } from './custom-stepper.component'
9import { SignupSharedModule } from '@app/+signup/shared/signup-shared.module'
10
11@NgModule({
12 imports: [
13 RegisterRoutingModule,
14 SharedModule,
15 CdkStepperModule,
16 SignupSharedModule
17 ],
18
19 declarations: [
20 RegisterComponent,
21 CustomStepperComponent,
22 RegisterStepChannelComponent,
23 RegisterStepUserComponent
24 ],
25
26 exports: [
27 RegisterComponent
28 ],
29
30 providers: [
31 ]
32})
33export class RegisterModule { }
diff --git a/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.html b/client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.html
index 2e4180632..2e4180632 100644
--- a/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.html
+++ b/client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.html
diff --git a/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.scss b/client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.scss
index efec6b706..efec6b706 100644
--- a/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.scss
+++ b/client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.scss
diff --git a/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts b/client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts
index cfd471fa4..cfd471fa4 100644
--- a/client/src/app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts
+++ b/client/src/app/+signup/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component.ts
diff --git a/client/src/app/+verify-account/verify-account-email/verify-account-email.component.html b/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.html
index a83d4a3c2..728709ca6 100644
--- a/client/src/app/+verify-account/verify-account-email/verify-account-email.component.html
+++ b/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.html
@@ -3,9 +3,9 @@
3 Verify account email confirmation 3 Verify account email confirmation
4 </div> 4 </div>
5 5
6 <div i18n *ngIf="success; else verificationError"> 6 <my-signup-success i18n *ngIf="success; else verificationError" message="Your email has been verified and you may now login.">
7 Your email has been verified and you may now login. Redirecting... 7 </my-signup-success>
8 </div> 8
9 <ng-template #verificationError> 9 <ng-template #verificationError>
10 <div> 10 <div>
11 <span i18n>An error occurred. </span> 11 <span i18n>An error occurred. </span>
diff --git a/client/src/app/+verify-account/verify-account-email/verify-account-email.component.ts b/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts
index f9ecf664b..3fb2d1cd8 100644
--- a/client/src/app/+verify-account/verify-account-email/verify-account-email.component.ts
+++ b/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.ts
@@ -40,9 +40,6 @@ export class VerifyAccountEmailComponent implements OnInit {
40 .subscribe( 40 .subscribe(
41 () => { 41 () => {
42 this.success = true 42 this.success = true
43 setTimeout(() => {
44 this.router.navigate([ '/login' ])
45 }, 2000)
46 }, 43 },
47 44
48 err => { 45 err => {
diff --git a/client/src/app/+verify-account/verify-account-routing.module.ts b/client/src/app/+signup/+verify-account/verify-account-routing.module.ts
index a038f0336..16d5fe0d0 100644
--- a/client/src/app/+verify-account/verify-account-routing.module.ts
+++ b/client/src/app/+signup/+verify-account/verify-account-routing.module.ts
@@ -1,12 +1,8 @@
1import { NgModule } from '@angular/core' 1import { NgModule } from '@angular/core'
2import { RouterModule, Routes } from '@angular/router' 2import { RouterModule, Routes } from '@angular/router'
3
4import { MetaGuard } from '@ngx-meta/core' 3import { MetaGuard } from '@ngx-meta/core'
5 4import { VerifyAccountEmailComponent } from './verify-account-email/verify-account-email.component'
6import { VerifyAccountEmailComponent } from '@app/+verify-account/verify-account-email/verify-account-email.component' 5import { VerifyAccountAskSendEmailComponent } from './verify-account-ask-send-email/verify-account-ask-send-email.component'
7import {
8 VerifyAccountAskSendEmailComponent
9} from '@app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component'
10 6
11const verifyAccountRoutes: Routes = [ 7const verifyAccountRoutes: Routes = [
12 { 8 {
diff --git a/client/src/app/+signup/+verify-account/verify-account.module.ts b/client/src/app/+signup/+verify-account/verify-account.module.ts
new file mode 100644
index 000000000..9fe14e81e
--- /dev/null
+++ b/client/src/app/+signup/+verify-account/verify-account.module.ts
@@ -0,0 +1,25 @@
1import { NgModule } from '@angular/core'
2import { VerifyAccountRoutingModule } from './verify-account-routing.module'
3import { VerifyAccountEmailComponent } from './verify-account-email/verify-account-email.component'
4import { VerifyAccountAskSendEmailComponent } from './verify-account-ask-send-email/verify-account-ask-send-email.component'
5import { SharedModule } from '@app/shared'
6import { SignupSharedModule } from '@app/+signup/shared/signup-shared.module'
7
8@NgModule({
9 imports: [
10 VerifyAccountRoutingModule,
11 SharedModule,
12 SignupSharedModule
13 ],
14
15 declarations: [
16 VerifyAccountEmailComponent,
17 VerifyAccountAskSendEmailComponent
18 ],
19
20 exports: [],
21
22 providers: []
23})
24export class VerifyAccountModule {
25}
diff --git a/client/src/app/+signup/shared/signup-shared.module.ts b/client/src/app/+signup/shared/signup-shared.module.ts
new file mode 100644
index 000000000..cd21fdef3
--- /dev/null
+++ b/client/src/app/+signup/shared/signup-shared.module.ts
@@ -0,0 +1,21 @@
1import { NgModule } from '@angular/core'
2import { SignupSuccessComponent } from '../shared/signup-success.component'
3import { SharedModule } from '@app/shared'
4
5@NgModule({
6 imports: [
7 SharedModule
8 ],
9
10 declarations: [
11 SignupSuccessComponent
12 ],
13
14 exports: [
15 SignupSuccessComponent
16 ],
17
18 providers: [
19 ]
20})
21export class SignupSharedModule { }
diff --git a/client/src/app/+signup/shared/signup-success.component.html b/client/src/app/+signup/shared/signup-success.component.html
new file mode 100644
index 000000000..e35f858c6
--- /dev/null
+++ b/client/src/app/+signup/shared/signup-success.component.html
@@ -0,0 +1,16 @@
1<!-- Thanks: Amit Singh Sansoya from https://codepen.io/amit3200/pen/zWMJOO -->
2
3<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130.2 130.2">
4 <circle class="path circle" fill="none" stroke="#73AF55" stroke-width="6" stroke-miterlimit="10" cx="65.1" cy="65.1" r="62.1"/>
5 <polyline class="path check" fill="none" stroke="#73AF55" stroke-width="6" stroke-linecap="round" stroke-miterlimit="10" points="100.2,40.2 51.5,88.8 29.8,67.5 "/>
6</svg>
7
8<p class="bottom-message">Welcome on PeerTube!</p>
9
10<div *ngIf="message" class="alert alert-success">
11 <p>{{ message }}</p>
12
13 <p i18n>
14 If you need help to use PeerTube, you can take a look to the <a href="https://docs.joinpeertube.org/#/use-setup-account" target="_blank" rel="noopener noreferrer">documentation</a>.
15 </p>
16</div>
diff --git a/client/src/app/+signup/shared/signup-success.component.scss b/client/src/app/+signup/shared/signup-success.component.scss
new file mode 100644
index 000000000..fbc27c8bc
--- /dev/null
+++ b/client/src/app/+signup/shared/signup-success.component.scss
@@ -0,0 +1,76 @@
1svg {
2 width: 100px;
3 display: block;
4 margin: 40px auto 0;
5}
6
7.path {
8 stroke-dasharray: 1000;
9 stroke-dashoffset: 0;
10
11 &.circle {
12 -webkit-animation: dash .9s ease-in-out;
13 animation: dash .9s ease-in-out;
14 }
15
16 &.line {
17 stroke-dashoffset: 1000;
18 -webkit-animation: dash .9s .35s ease-in-out forwards;
19 animation: dash .9s .35s ease-in-out forwards;
20 }
21
22 &.check {
23 stroke-dashoffset: -100;
24 -webkit-animation: dash-check .9s .35s ease-in-out forwards;
25 animation: dash-check .9s .35s ease-in-out forwards;
26 }
27}
28
29.bottom-message {
30 text-align: center;
31 margin: 20px 0 60px;
32 font-size: 1.25em;
33 color: #73AF55;
34}
35
36.alert {
37 font-size: 15px;
38 text-align: center;
39}
40
41
42@-webkit-keyframes dash {
43 0% {
44 stroke-dashoffset: 1000;
45 }
46 100% {
47 stroke-dashoffset: 0;
48 }
49}
50
51@keyframes dash {
52 0% {
53 stroke-dashoffset: 1000;
54 }
55 100% {
56 stroke-dashoffset: 0;
57 }
58}
59
60@-webkit-keyframes dash-check {
61 0% {
62 stroke-dashoffset: -100;
63 }
64 100% {
65 stroke-dashoffset: 900;
66 }
67}
68
69@keyframes dash-check {
70 0% {
71 stroke-dashoffset: -100;
72 }
73 100% {
74 stroke-dashoffset: 900;
75 }
76}
diff --git a/client/src/app/+signup/shared/signup-success.component.ts b/client/src/app/+signup/shared/signup-success.component.ts
new file mode 100644
index 000000000..19fb5922a
--- /dev/null
+++ b/client/src/app/+signup/shared/signup-success.component.ts
@@ -0,0 +1,10 @@
1import { Component, Input } from '@angular/core'
2
3@Component({
4 selector: 'my-signup-success',
5 templateUrl: './signup-success.component.html',
6 styleUrls: [ './signup-success.component.scss' ]
7})
8export class SignupSuccessComponent {
9 @Input() message: string
10}
diff --git a/client/src/app/+verify-account/index.ts b/client/src/app/+verify-account/index.ts
deleted file mode 100644
index 733f5ba77..000000000
--- a/client/src/app/+verify-account/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
1export * from '@app/+verify-account/verify-account-routing.module'
2export * from '@app/+verify-account/verify-account.module'
diff --git a/client/src/app/+verify-account/verify-account.module.ts b/client/src/app/+verify-account/verify-account.module.ts
deleted file mode 100644
index 9092c6b4f..000000000
--- a/client/src/app/+verify-account/verify-account.module.ts
+++ /dev/null
@@ -1,27 +0,0 @@
1import { NgModule } from '@angular/core'
2
3import { VerifyAccountRoutingModule } from '@app/+verify-account/verify-account-routing.module'
4import { VerifyAccountEmailComponent } from '@app/+verify-account/verify-account-email/verify-account-email.component'
5import {
6 VerifyAccountAskSendEmailComponent
7} from '@app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component'
8import { SharedModule } from '@app/shared'
9
10@NgModule({
11 imports: [
12 VerifyAccountRoutingModule,
13 SharedModule
14 ],
15
16 declarations: [
17 VerifyAccountEmailComponent,
18 VerifyAccountAskSendEmailComponent
19 ],
20
21 exports: [
22 ],
23
24 providers: [
25 ]
26})
27export class VerifyAccountModule { }
diff --git a/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts b/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts
index 907aefae1..7990044a2 100644
--- a/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts
+++ b/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts
@@ -5,7 +5,7 @@ import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
5import { Subscription } from 'rxjs' 5import { Subscription } from 'rxjs'
6import { Notifier } from '@app/core' 6import { Notifier } from '@app/core'
7import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' 7import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
8import { ComponentPagination } from '@app/shared/rest/component-pagination.model' 8import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model'
9import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' 9import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
10 10
11@Component({ 11@Component({
@@ -46,8 +46,7 @@ export class VideoChannelPlaylistsComponent implements OnInit, OnDestroy {
46 } 46 }
47 47
48 onNearOfBottom () { 48 onNearOfBottom () {
49 // Last page 49 if (!hasMoreItems(this.pagination)) return
50 if (this.pagination.totalItems <= (this.pagination.currentPage * this.pagination.itemsPerPage)) return
51 50
52 this.pagination.currentPage += 1 51 this.pagination.currentPage += 1
53 this.loadVideoPlaylists() 52 this.loadVideoPlaylists()
diff --git a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
index 5e60b34b4..629fd4450 100644
--- a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
+++ b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
@@ -29,6 +29,7 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
29 private videoChannelSub: Subscription 29 private videoChannelSub: Subscription
30 30
31 constructor ( 31 constructor (
32 protected i18n: I18n,
32 protected router: Router, 33 protected router: Router,
33 protected serverService: ServerService, 34 protected serverService: ServerService,
34 protected route: ActivatedRoute, 35 protected route: ActivatedRoute,
@@ -36,7 +37,6 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
36 protected notifier: Notifier, 37 protected notifier: Notifier,
37 protected confirmService: ConfirmService, 38 protected confirmService: ConfirmService,
38 protected screenService: ScreenService, 39 protected screenService: ScreenService,
39 private i18n: I18n,
40 private videoChannelService: VideoChannelService, 40 private videoChannelService: VideoChannelService,
41 private videoService: VideoService 41 private videoService: VideoService
42 ) { 42 ) {
diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts
index db8888dba..7ca51f226 100644
--- a/client/src/app/app-routing.module.ts
+++ b/client/src/app/app-routing.module.ts
@@ -16,7 +16,7 @@ const routes: Routes = [
16 }, 16 },
17 { 17 {
18 path: 'verify-account', 18 path: 'verify-account',
19 loadChildren: './+verify-account/verify-account.module#VerifyAccountModule' 19 loadChildren: './+signup/+verify-account/verify-account.module#VerifyAccountModule'
20 }, 20 },
21 { 21 {
22 path: 'accounts', 22 path: 'accounts',
@@ -31,6 +31,10 @@ const routes: Routes = [
31 loadChildren: './+about/about.module#AboutModule' 31 loadChildren: './+about/about.module#AboutModule'
32 }, 32 },
33 { 33 {
34 path: 'signup',
35 loadChildren: './+signup/+register/register.module#RegisterModule'
36 },
37 {
34 path: '', 38 path: '',
35 component: AppComponent // Avoid 404, app component will redirect dynamically 39 component: AppComponent // Avoid 404, app component will redirect dynamically
36 }, 40 },
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts
index 0bbc2e08b..1e2936a37 100644
--- a/client/src/app/app.module.ts
+++ b/client/src/app/app.module.ts
@@ -14,7 +14,6 @@ import { HeaderComponent } from './header'
14import { LoginModule } from './login' 14import { LoginModule } from './login'
15import { AvatarNotificationComponent, LanguageChooserComponent, MenuComponent } from './menu' 15import { AvatarNotificationComponent, LanguageChooserComponent, MenuComponent } from './menu'
16import { SharedModule } from './shared' 16import { SharedModule } from './shared'
17import { SignupModule } from './signup'
18import { VideosModule } from './videos' 17import { VideosModule } from './videos'
19import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '../../../shared/models/i18n' 18import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '../../../shared/models/i18n'
20import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' 19import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
@@ -53,7 +52,6 @@ export function metaFactory (serverService: ServerService): MetaLoader {
53 CoreModule, 52 CoreModule,
54 LoginModule, 53 LoginModule,
55 ResetPasswordModule, 54 ResetPasswordModule,
56 SignupModule,
57 SearchModule, 55 SearchModule,
58 SharedModule, 56 SharedModule,
59 VideosModule, 57 VideosModule,
diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts
index d3e72afb4..06fa8fcf1 100644
--- a/client/src/app/core/core.module.ts
+++ b/client/src/app/core/core.module.ts
@@ -20,6 +20,7 @@ import { Notifier } from './notification'
20import { MessageService } from 'primeng/api' 20import { MessageService } from 'primeng/api'
21import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service' 21import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service'
22import { ServerConfigResolver } from './routing/server-config-resolver.service' 22import { ServerConfigResolver } from './routing/server-config-resolver.service'
23import { UnloggedGuard } from '@app/core/routing/unlogged-guard.service'
23 24
24@NgModule({ 25@NgModule({
25 imports: [ 26 imports: [
@@ -58,6 +59,8 @@ import { ServerConfigResolver } from './routing/server-config-resolver.service'
58 ThemeService, 59 ThemeService,
59 LoginGuard, 60 LoginGuard,
60 UserRightGuard, 61 UserRightGuard,
62 UnloggedGuard,
63
61 RedirectService, 64 RedirectService,
62 Notifier, 65 Notifier,
63 MessageService, 66 MessageService,
diff --git a/client/src/app/core/routing/redirect.service.ts b/client/src/app/core/routing/redirect.service.ts
index e1db4097b..571822b76 100644
--- a/client/src/app/core/routing/redirect.service.ts
+++ b/client/src/app/core/routing/redirect.service.ts
@@ -42,7 +42,14 @@ export class RedirectService {
42 } 42 }
43 43
44 redirectToPreviousRoute () { 44 redirectToPreviousRoute () {
45 if (this.previousUrl) return this.router.navigateByUrl(this.previousUrl) 45 const exceptions = [
46 '/verify-account'
47 ]
48
49 if (this.previousUrl) {
50 const isException = exceptions.find(e => this.previousUrl.startsWith(e))
51 if (!isException) return this.router.navigateByUrl(this.previousUrl)
52 }
46 53
47 return this.redirectToHomepage() 54 return this.redirectToHomepage()
48 } 55 }
diff --git a/client/src/app/core/routing/unlogged-guard.service.ts b/client/src/app/core/routing/unlogged-guard.service.ts
new file mode 100644
index 000000000..3132a1a77
--- /dev/null
+++ b/client/src/app/core/routing/unlogged-guard.service.ts
@@ -0,0 +1,25 @@
1import { Injectable } from '@angular/core'
2import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router'
3import { AuthService } from '../auth/auth.service'
4import { RedirectService } from './redirect.service'
5
6@Injectable()
7export class UnloggedGuard implements CanActivate, CanActivateChild {
8
9 constructor (
10 private router: Router,
11 private auth: AuthService,
12 private redirectService: RedirectService
13 ) {}
14
15 canActivate (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
16 if (this.auth.isLoggedIn() === false) return true
17
18 this.redirectService.redirectToHomepage()
19 return false
20 }
21
22 canActivateChild (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
23 return this.canActivate(route, state)
24 }
25}
diff --git a/client/src/app/shared/actor/actor.model.ts b/client/src/app/shared/actor/actor.model.ts
index adecec1fc..5a517c975 100644
--- a/client/src/app/shared/actor/actor.model.ts
+++ b/client/src/app/shared/actor/actor.model.ts
@@ -4,7 +4,6 @@ import { getAbsoluteAPIUrl } from '@app/shared/misc/utils'
4 4
5export abstract class Actor implements ActorServer { 5export abstract class Actor implements ActorServer {
6 id: number 6 id: number
7 uuid: string
8 url: string 7 url: string
9 name: string 8 name: string
10 host: string 9 host: string
@@ -35,7 +34,6 @@ export abstract class Actor implements ActorServer {
35 34
36 protected constructor (hash: ActorServer) { 35 protected constructor (hash: ActorServer) {
37 this.id = hash.id 36 this.id = hash.id
38 this.uuid = hash.uuid
39 this.url = hash.url 37 this.url = hash.url
40 this.name = hash.name 38 this.name = hash.name
41 this.host = hash.host 39 this.host = hash.host
diff --git a/client/src/app/shared/buttons/button.component.scss b/client/src/app/shared/buttons/button.component.scss
index 04199a2a9..99d7f51c1 100644
--- a/client/src/app/shared/buttons/button.component.scss
+++ b/client/src/app/shared/buttons/button.component.scss
@@ -5,16 +5,9 @@
5 @include peertube-button-link; 5 @include peertube-button-link;
6 @include button-with-icon(21px, 0, -2px); 6 @include button-with-icon(21px, 0, -2px);
7 7
8 font-weight: $font-semibold; 8 // FIXME: Firefox does not apply global .orange-button icon color
9 color: $grey-foreground-color; 9 &.orange-button {
10 background-color: $grey-background-color; 10 @include apply-svg-color(#fff)
11
12 &:hover {
13 background-color: $grey-background-hover-color;
14 }
15
16 my-global-icon {
17 @include apply-svg-color($grey-foreground-color);
18 } 11 }
19} 12}
20 13
diff --git a/client/src/app/shared/buttons/button.component.ts b/client/src/app/shared/buttons/button.component.ts
index c2b69d31a..cf334e8d5 100644
--- a/client/src/app/shared/buttons/button.component.ts
+++ b/client/src/app/shared/buttons/button.component.ts
@@ -9,7 +9,7 @@ import { GlobalIconName } from '@app/shared/images/global-icon.component'
9 9
10export class ButtonComponent { 10export class ButtonComponent {
11 @Input() label = '' 11 @Input() label = ''
12 @Input() className: string = undefined 12 @Input() className = 'grey-button'
13 @Input() icon: GlobalIconName = undefined 13 @Input() icon: GlobalIconName = undefined
14 @Input() title: string = undefined 14 @Input() title: string = undefined
15 15
diff --git a/client/src/app/shared/buttons/delete-button.component.html b/client/src/app/shared/buttons/delete-button.component.html
index b4acb9d32..25196fbd5 100644
--- a/client/src/app/shared/buttons/delete-button.component.html
+++ b/client/src/app/shared/buttons/delete-button.component.html
@@ -1,4 +1,4 @@
1<span class="action-button action-button-delete" [title]="title" role="button"> 1<span class="action-button action-button-delete grey-button" [title]="title" role="button">
2 <my-global-icon iconName="delete"></my-global-icon> 2 <my-global-icon iconName="delete"></my-global-icon>
3 3
4 <span class="button-label" *ngIf="label">{{ label }}</span> 4 <span class="button-label" *ngIf="label">{{ label }}</span>
diff --git a/client/src/app/shared/buttons/edit-button.component.html b/client/src/app/shared/buttons/edit-button.component.html
index da3addbae..3d7cd4780 100644
--- a/client/src/app/shared/buttons/edit-button.component.html
+++ b/client/src/app/shared/buttons/edit-button.component.html
@@ -1,4 +1,4 @@
1<a class="action-button action-button-edit" [routerLink]="routerLink" i18n-title title="Edit"> 1<a class="action-button action-button-edit grey-button" [routerLink]="routerLink" i18n-title title="Edit">
2 <my-global-icon iconName="edit"></my-global-icon> 2 <my-global-icon iconName="edit"></my-global-icon>
3 3
4 <span class="button-label" *ngIf="label">{{ label }}</span> 4 <span class="button-label" *ngIf="label">{{ label }}</span>
diff --git a/client/src/app/shared/forms/peertube-checkbox.component.scss b/client/src/app/shared/forms/peertube-checkbox.component.scss
index ea321ee65..84ea788af 100644
--- a/client/src/app/shared/forms/peertube-checkbox.component.scss
+++ b/client/src/app/shared/forms/peertube-checkbox.component.scss
@@ -14,9 +14,6 @@
14 14
15 input { 15 input {
16 @include peertube-checkbox(1px); 16 @include peertube-checkbox(1px);
17
18 width: 10px;
19 margin-right: 10px;
20 } 17 }
21 } 18 }
22 19
diff --git a/client/src/app/shared/forms/reactive-file.component.html b/client/src/app/shared/forms/reactive-file.component.html
index 7d691059d..f6bf5f9ae 100644
--- a/client/src/app/shared/forms/reactive-file.component.html
+++ b/client/src/app/shared/forms/reactive-file.component.html
@@ -1,6 +1,9 @@
1<div class="root"> 1<div class="root">
2 <div class="button-file"> 2 <div class="button-file" [ngClass]="{ 'with-icon': !!icon }">
3 <my-global-icon *ngIf="icon" [iconName]="icon"></my-global-icon>
4
3 <span>{{ inputLabel }}</span> 5 <span>{{ inputLabel }}</span>
6
4 <input 7 <input
5 type="file" 8 type="file"
6 [name]="inputName" [id]="inputName" [accept]="extensions" 9 [name]="inputName" [id]="inputName" [accept]="extensions"
@@ -8,7 +11,5 @@
8 /> 11 />
9 </div> 12 </div>
10 13
11 <div i18n class="file-constraints">(extensions: {{ allowedExtensionsMessage }}, max size: {{ maxFileSize | bytes }})</div>
12
13 <div class="filename" *ngIf="displayFilename === true && filename">{{ filename }}</div> 14 <div class="filename" *ngIf="displayFilename === true && filename">{{ filename }}</div>
14</div> 15</div>
diff --git a/client/src/app/shared/forms/reactive-file.component.scss b/client/src/app/shared/forms/reactive-file.component.scss
index d89844264..84c23c1d6 100644
--- a/client/src/app/shared/forms/reactive-file.component.scss
+++ b/client/src/app/shared/forms/reactive-file.component.scss
@@ -8,13 +8,11 @@
8 8
9 .button-file { 9 .button-file {
10 @include peertube-button-file(auto); 10 @include peertube-button-file(auto);
11 @include grey-button;
11 12
12 min-width: 190px; 13 &.with-icon {
13 } 14 @include button-with-icon;
14 15 }
15 .file-constraints {
16 margin-left: 5px;
17 font-size: 13px;
18 } 16 }
19 17
20 .filename { 18 .filename {
diff --git a/client/src/app/shared/forms/reactive-file.component.ts b/client/src/app/shared/forms/reactive-file.component.ts
index f60c38e8d..b7a821d4f 100644
--- a/client/src/app/shared/forms/reactive-file.component.ts
+++ b/client/src/app/shared/forms/reactive-file.component.ts
@@ -2,6 +2,7 @@ import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@ang
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' 2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3import { Notifier } from '@app/core' 3import { Notifier } from '@app/core'
4import { I18n } from '@ngx-translate/i18n-polyfill' 4import { I18n } from '@ngx-translate/i18n-polyfill'
5import { GlobalIconName } from '@app/shared/images/global-icon.component'
5 6
6@Component({ 7@Component({
7 selector: 'my-reactive-file', 8 selector: 'my-reactive-file',
@@ -21,6 +22,7 @@ export class ReactiveFileComponent implements OnInit, ControlValueAccessor {
21 @Input() extensions: string[] = [] 22 @Input() extensions: string[] = []
22 @Input() maxFileSize: number 23 @Input() maxFileSize: number
23 @Input() displayFilename = false 24 @Input() displayFilename = false
25 @Input() icon: GlobalIconName
24 26
25 @Output() fileChanged = new EventEmitter<Blob>() 27 @Output() fileChanged = new EventEmitter<Blob>()
26 28
diff --git a/client/src/app/shared/images/image-upload.component.html b/client/src/app/shared/images/image-upload.component.html
deleted file mode 100644
index c09c862c4..000000000
--- a/client/src/app/shared/images/image-upload.component.html
+++ /dev/null
@@ -1,9 +0,0 @@
1<div class="root">
2 <my-reactive-file
3 [inputName]="inputName" [inputLabel]="inputLabel" [extensions]="videoImageExtensions" [maxFileSize]="maxVideoImageSize"
4 (fileChanged)="onFileChanged($event)"
5 ></my-reactive-file>
6
7 <img *ngIf="imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" [src]="imageSrc" class="preview" />
8 <div *ngIf="!imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" class="preview no-image"></div>
9</div>
diff --git a/client/src/app/shared/images/image-upload.component.scss b/client/src/app/shared/images/image-upload.component.scss
deleted file mode 100644
index b63963bca..000000000
--- a/client/src/app/shared/images/image-upload.component.scss
+++ /dev/null
@@ -1,18 +0,0 @@
1@import '_variables';
2@import '_mixins';
3
4.root {
5 height: auto;
6 display: flex;
7 align-items: center;
8
9 .preview {
10 border: 2px solid grey;
11 border-radius: 4px;
12 margin-left: 50px;
13
14 &.no-image {
15 background-color: #ececec;
16 }
17 }
18}
diff --git a/client/src/app/shared/images/preview-upload.component.html b/client/src/app/shared/images/preview-upload.component.html
new file mode 100644
index 000000000..5e1d5211b
--- /dev/null
+++ b/client/src/app/shared/images/preview-upload.component.html
@@ -0,0 +1,13 @@
1<div class="root">
2 <div class="preview-container">
3 <my-reactive-file
4 [inputName]="inputName" [inputLabel]="inputLabel" [extensions]="videoImageExtensions" [maxFileSize]="maxVideoImageSize"
5 icon="edit" (fileChanged)="onFileChanged($event)"
6 ></my-reactive-file>
7
8 <img *ngIf="imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" [src]="imageSrc" class="preview" />
9 <div *ngIf="!imageSrc" [ngStyle]="{ width: previewWidth, height: previewHeight }" class="preview no-image"></div>
10 </div>
11
12 <div i18n class="file-constraints">(extensions: {{ allowedExtensionsMessage }}, max size: {{ maxVideoImageSize | bytes }})</div>
13</div>
diff --git a/client/src/app/shared/images/preview-upload.component.scss b/client/src/app/shared/images/preview-upload.component.scss
new file mode 100644
index 000000000..257060239
--- /dev/null
+++ b/client/src/app/shared/images/preview-upload.component.scss
@@ -0,0 +1,27 @@
1@import '_variables';
2@import '_mixins';
3
4.root {
5 height: auto;
6 display: flex;
7 flex-direction: column;
8
9 .preview-container {
10 position: relative;
11
12 my-reactive-file {
13 position: absolute;
14 bottom: 10px;
15 left: 10px;
16 }
17
18 .preview {
19 border: 2px solid grey;
20 border-radius: 4px;
21
22 &.no-image {
23 background-color: #ececec;
24 }
25 }
26 }
27}
diff --git a/client/src/app/shared/images/image-upload.component.ts b/client/src/app/shared/images/preview-upload.component.ts
index 2da1592ff..44b78866e 100644
--- a/client/src/app/shared/images/image-upload.component.ts
+++ b/client/src/app/shared/images/preview-upload.component.ts
@@ -1,27 +1,28 @@
1import { Component, forwardRef, Input } from '@angular/core' 1import { Component, forwardRef, Input, OnInit } from '@angular/core'
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' 2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser' 3import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'
4import { ServerService } from '@app/core' 4import { ServerService } from '@app/core'
5 5
6@Component({ 6@Component({
7 selector: 'my-image-upload', 7 selector: 'my-preview-upload',
8 styleUrls: [ './image-upload.component.scss' ], 8 styleUrls: [ './preview-upload.component.scss' ],
9 templateUrl: './image-upload.component.html', 9 templateUrl: './preview-upload.component.html',
10 providers: [ 10 providers: [
11 { 11 {
12 provide: NG_VALUE_ACCESSOR, 12 provide: NG_VALUE_ACCESSOR,
13 useExisting: forwardRef(() => ImageUploadComponent), 13 useExisting: forwardRef(() => PreviewUploadComponent),
14 multi: true 14 multi: true
15 } 15 }
16 ] 16 ]
17}) 17})
18export class ImageUploadComponent implements ControlValueAccessor { 18export class PreviewUploadComponent implements OnInit, ControlValueAccessor {
19 @Input() inputLabel: string 19 @Input() inputLabel: string
20 @Input() inputName: string 20 @Input() inputName: string
21 @Input() previewWidth: string 21 @Input() previewWidth: string
22 @Input() previewHeight: string 22 @Input() previewHeight: string
23 23
24 imageSrc: SafeResourceUrl 24 imageSrc: SafeResourceUrl
25 allowedExtensionsMessage = ''
25 26
26 private file: File 27 private file: File
27 28
@@ -38,6 +39,10 @@ export class ImageUploadComponent implements ControlValueAccessor {
38 return this.serverService.getConfig().video.image.size.max 39 return this.serverService.getConfig().video.image.size.max
39 } 40 }
40 41
42 ngOnInit () {
43 this.allowedExtensionsMessage = this.videoImageExtensions.join(', ')
44 }
45
41 onFileChanged (file: File) { 46 onFileChanged (file: File) {
42 this.file = file 47 this.file = file
43 48
diff --git a/client/src/app/+admin/follows/shared/follow.service.ts b/client/src/app/shared/instance/follow.service.ts
index c2b8ef006..5a44c64f1 100644
--- a/client/src/app/+admin/follows/shared/follow.service.ts
+++ b/client/src/app/shared/instance/follow.service.ts
@@ -3,13 +3,13 @@ import { HttpClient, HttpParams } from '@angular/common/http'
3import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
4import { SortMeta } from 'primeng/primeng' 4import { SortMeta } from 'primeng/primeng'
5import { Observable } from 'rxjs' 5import { Observable } from 'rxjs'
6import { ActorFollow, ResultList } from '../../../../../../shared' 6import { ActorFollow, ResultList } from '@shared/index'
7import { environment } from '../../../../environments/environment' 7import { environment } from '../../../environments/environment'
8import { RestExtractor, RestPagination, RestService } from '../../../shared' 8import { RestExtractor, RestPagination, RestService } from '../rest'
9 9
10@Injectable() 10@Injectable()
11export class FollowService { 11export class FollowService {
12 private static BASE_APPLICATION_URL = environment.apiUrl + '/api/v1/server' 12 private static BASE_APPLICATION_URL = 'https://peertube2.cpy.re' + '/api/v1/server'
13 13
14 constructor ( 14 constructor (
15 private authHttp: HttpClient, 15 private authHttp: HttpClient,
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts
index ded65653f..1d49c7bc8 100644
--- a/client/src/app/shared/shared.module.ts
+++ b/client/src/app/shared/shared.module.ts
@@ -69,7 +69,7 @@ import { HtmlRendererService, LinkifierService, MarkdownService } from '@app/sha
69import { ConfirmComponent } from '@app/shared/confirm/confirm.component' 69import { ConfirmComponent } from '@app/shared/confirm/confirm.component'
70import { SmallLoaderComponent } from '@app/shared/misc/small-loader.component' 70import { SmallLoaderComponent } from '@app/shared/misc/small-loader.component'
71import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' 71import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
72import { ImageUploadComponent } from '@app/shared/images/image-upload.component' 72import { PreviewUploadComponent } from '@app/shared/images/preview-upload.component'
73import { GlobalIconComponent } from '@app/shared/images/global-icon.component' 73import { GlobalIconComponent } from '@app/shared/images/global-icon.component'
74import { VideoPlaylistMiniatureComponent } from '@app/shared/video-playlist/video-playlist-miniature.component' 74import { VideoPlaylistMiniatureComponent } from '@app/shared/video-playlist/video-playlist-miniature.component'
75import { VideoAddToPlaylistComponent } from '@app/shared/video-playlist/video-add-to-playlist.component' 75import { VideoAddToPlaylistComponent } from '@app/shared/video-playlist/video-add-to-playlist.component'
@@ -85,6 +85,7 @@ import { VideoBlacklistComponent } from '@app/shared/video/modals/video-blacklis
85import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component' 85import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component'
86import { VideoReportComponent } from '@app/shared/video/modals/video-report.component' 86import { VideoReportComponent } from '@app/shared/video/modals/video-report.component'
87import { ClipboardModule } from 'ngx-clipboard' 87import { ClipboardModule } from 'ngx-clipboard'
88import { FollowService } from '@app/shared/instance/follow.service'
88 89
89@NgModule({ 90@NgModule({
90 imports: [ 91 imports: [
@@ -154,7 +155,7 @@ import { ClipboardModule } from 'ngx-clipboard'
154 ConfirmComponent, 155 ConfirmComponent,
155 156
156 GlobalIconComponent, 157 GlobalIconComponent,
157 ImageUploadComponent 158 PreviewUploadComponent
158 ], 159 ],
159 160
160 exports: [ 161 exports: [
@@ -218,7 +219,7 @@ import { ClipboardModule } from 'ngx-clipboard'
218 ConfirmComponent, 219 ConfirmComponent,
219 220
220 GlobalIconComponent, 221 GlobalIconComponent,
221 ImageUploadComponent, 222 PreviewUploadComponent,
222 223
223 NumberFormatterPipe, 224 NumberFormatterPipe,
224 ObjectLengthPipe, 225 ObjectLengthPipe,
@@ -271,6 +272,8 @@ import { ClipboardModule } from 'ngx-clipboard'
271 272
272 UserNotificationService, 273 UserNotificationService,
273 274
275 FollowService,
276
274 I18n 277 I18n
275 ] 278 ]
276}) 279})
diff --git a/client/src/app/shared/users/user.service.ts b/client/src/app/shared/users/user.service.ts
index cc5c051f1..20883456f 100644
--- a/client/src/app/shared/users/user.service.ts
+++ b/client/src/app/shared/users/user.service.ts
@@ -9,6 +9,7 @@ import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
9import { SortMeta } from 'primeng/api' 9import { SortMeta } from 'primeng/api'
10import { BytesPipe } from 'ngx-pipes' 10import { BytesPipe } from 'ngx-pipes'
11import { I18n } from '@ngx-translate/i18n-polyfill' 11import { I18n } from '@ngx-translate/i18n-polyfill'
12import { UserRegister } from '@shared/models/users/user-register.model'
12 13
13@Injectable() 14@Injectable()
14export class UserService { 15export class UserService {
@@ -64,7 +65,7 @@ export class UserService {
64 .pipe(catchError(err => this.restExtractor.handleError(err))) 65 .pipe(catchError(err => this.restExtractor.handleError(err)))
65 } 66 }
66 67
67 signup (userCreate: UserCreate) { 68 signup (userCreate: UserRegister) {
68 return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate) 69 return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate)
69 .pipe( 70 .pipe(
70 map(this.restExtractor.extractDataBool), 71 map(this.restExtractor.extractDataBool),
diff --git a/client/src/app/shared/video-channel/video-channel.service.ts b/client/src/app/shared/video-channel/video-channel.service.ts
index d0bec649a..0168d37d9 100644
--- a/client/src/app/shared/video-channel/video-channel.service.ts
+++ b/client/src/app/shared/video-channel/video-channel.service.ts
@@ -2,7 +2,7 @@ import { catchError, map, tap } from 'rxjs/operators'
2import { Injectable } from '@angular/core' 2import { Injectable } from '@angular/core'
3import { Observable, ReplaySubject } from 'rxjs' 3import { Observable, ReplaySubject } from 'rxjs'
4import { RestExtractor } from '../rest/rest-extractor.service' 4import { RestExtractor } from '../rest/rest-extractor.service'
5import { HttpClient } from '@angular/common/http' 5import { HttpClient, HttpParams } from '@angular/common/http'
6import { VideoChannel as VideoChannelServer, VideoChannelCreate, VideoChannelUpdate } from '../../../../../shared/models/videos' 6import { VideoChannel as VideoChannelServer, VideoChannelCreate, VideoChannelUpdate } from '../../../../../shared/models/videos'
7import { AccountService } from '../account/account.service' 7import { AccountService } from '../account/account.service'
8import { ResultList } from '../../../../../shared' 8import { ResultList } from '../../../../../shared'
@@ -10,6 +10,8 @@ import { VideoChannel } from './video-channel.model'
10import { environment } from '../../../environments/environment' 10import { environment } from '../../../environments/environment'
11import { Account } from '@app/shared/account/account.model' 11import { Account } from '@app/shared/account/account.model'
12import { Avatar } from '../../../../../shared/models/avatars/avatar.model' 12import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
13import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
14import { RestService } from '@app/shared/rest'
13 15
14@Injectable() 16@Injectable()
15export class VideoChannelService { 17export class VideoChannelService {
@@ -29,6 +31,7 @@ export class VideoChannelService {
29 31
30 constructor ( 32 constructor (
31 private authHttp: HttpClient, 33 private authHttp: HttpClient,
34 private restService: RestService,
32 private restExtractor: RestExtractor 35 private restExtractor: RestExtractor
33 ) { } 36 ) { }
34 37
@@ -41,8 +44,16 @@ export class VideoChannelService {
41 ) 44 )
42 } 45 }
43 46
44 listAccountVideoChannels (account: Account): Observable<ResultList<VideoChannel>> { 47 listAccountVideoChannels (account: Account, componentPagination?: ComponentPagination): Observable<ResultList<VideoChannel>> {
45 return this.authHttp.get<ResultList<VideoChannelServer>>(AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/video-channels') 48 const pagination = componentPagination
49 ? this.restService.componentPaginationToRestPagination(componentPagination)
50 : { start: 0, count: 20 }
51
52 let params = new HttpParams()
53 params = this.restService.addRestGetParams(params, pagination)
54
55 const url = AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/video-channels'
56 return this.authHttp.get<ResultList<VideoChannelServer>>(url, { params })
46 .pipe( 57 .pipe(
47 map(res => VideoChannelService.extractVideoChannels(res)), 58 map(res => VideoChannelService.extractVideoChannels(res)),
48 catchError(err => this.restExtractor.handleError(err)) 59 catchError(err => this.restExtractor.handleError(err))
diff --git a/client/src/app/shared/video/abstract-video-list.html b/client/src/app/shared/video/abstract-video-list.html
index 268677977..efd369bca 100644
--- a/client/src/app/shared/video/abstract-video-list.html
+++ b/client/src/app/shared/video/abstract-video-list.html
@@ -6,7 +6,7 @@
6 </div> 6 </div>
7 </div> 7 </div>
8 8
9 <my-feed [syndicationItems]="syndicationItems"></my-feed> 9 <my-feed *ngIf="titlePage" [syndicationItems]="syndicationItems"></my-feed>
10 10
11 <div class="moderation-block" *ngIf="displayModerationBlock"> 11 <div class="moderation-block" *ngIf="displayModerationBlock">
12 <my-peertube-checkbox 12 <my-peertube-checkbox
@@ -22,11 +22,17 @@
22 myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true" 22 myInfiniteScroller (nearOfBottom)="onNearOfBottom()" [autoInit]="true"
23 class="videos" 23 class="videos"
24 > 24 >
25 <my-video-miniature 25 <ng-container *ngFor="let video of videos; trackBy: videoById;">
26 *ngFor="let video of videos; trackBy: videoById" [video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType" 26 <div class="date-title" *ngIf="getCurrentGroupedDateLabel(video)">
27 [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions" 27 {{ getCurrentGroupedDateLabel(video) }}
28 (videoBlacklisted)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)" 28 </div>
29 > 29
30 </my-video-miniature> 30 <my-video-miniature
31 [video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType"
32 [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions"
33 (videoBlacklisted)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)"
34 >
35 </my-video-miniature>
36 </ng-container>
31 </div> 37 </div>
32</div> 38</div>
diff --git a/client/src/app/shared/video/abstract-video-list.scss b/client/src/app/shared/video/abstract-video-list.scss
index 9d481d6e4..98b80fdfd 100644
--- a/client/src/app/shared/video/abstract-video-list.scss
+++ b/client/src/app/shared/video/abstract-video-list.scss
@@ -24,33 +24,19 @@
24 } 24 }
25} 25}
26 26
27.margin-content { 27.date-title {
28 width: $video-miniature-width * 6; 28 font-size: 16px;
29 margin: auto !important; 29 font-weight: $font-semibold;
30 30 margin-bottom: 20px;
31 @media screen and (max-width: 1800px) { 31 margin-top: -10px;
32 width: $video-miniature-width * 5; 32 padding-top: 20px;
33 }
34 33
35 @media screen and (max-width: 1800px - $video-miniature-width) { 34 &:not(:first-child) {
36 width: $video-miniature-width * 4; 35 border-top: 1px solid $separator-border-color;
37 } 36 }
37}
38 38
39 @media screen and (max-width: 1800px - (2* $video-miniature-width)) { 39.margin-content {
40 width: $video-miniature-width * 3; 40 @include adapt-margin-content-width;
41 }
42
43 @media screen and (max-width: 1800px - (3* $video-miniature-width)) {
44 width: $video-miniature-width * 2;
45 }
46
47 @media screen and (max-width: 500px) {
48 width: auto;
49 margin: 0 !important;
50
51 .videos {
52 @include video-miniature-small-screen;
53 }
54 }
55} 41}
56 42
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts
index fa9d38735..dc8f9cda9 100644
--- a/client/src/app/shared/video/abstract-video-list.ts
+++ b/client/src/app/shared/video/abstract-video-list.ts
@@ -11,6 +11,17 @@ import { MiniatureDisplayOptions, OwnerDisplayType } from '@app/shared/video/vid
11import { Syndication } from '@app/shared/video/syndication.model' 11import { Syndication } from '@app/shared/video/syndication.model'
12import { Notifier, ServerService } from '@app/core' 12import { Notifier, ServerService } from '@app/core'
13import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' 13import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
14import { I18n } from '@ngx-translate/i18n-polyfill'
15import { isLastMonth, isLastWeek, isToday, isYesterday } from '@shared/core-utils/miscs/date'
16
17enum GroupDate {
18 UNKNOWN = 0,
19 TODAY = 1,
20 YESTERDAY = 2,
21 LAST_WEEK = 3,
22 LAST_MONTH = 4,
23 OLDER = 5
24}
14 25
15export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableForReuseHook { 26export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableForReuseHook {
16 pagination: ComponentPagination = { 27 pagination: ComponentPagination = {
@@ -31,6 +42,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
31 displayModerationBlock = false 42 displayModerationBlock = false
32 titleTooltip: string 43 titleTooltip: string
33 displayVideoActions = true 44 displayVideoActions = true
45 groupByDate = false
34 46
35 disabled = false 47 disabled = false
36 48
@@ -50,11 +62,15 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
50 protected abstract serverService: ServerService 62 protected abstract serverService: ServerService
51 protected abstract screenService: ScreenService 63 protected abstract screenService: ScreenService
52 protected abstract router: Router 64 protected abstract router: Router
65 protected abstract i18n: I18n
53 abstract titlePage: string 66 abstract titlePage: string
54 67
55 private resizeSubscription: Subscription 68 private resizeSubscription: Subscription
56 private angularState: number 69 private angularState: number
57 70
71 private groupedDateLabels: { [id in GroupDate]: string }
72 private groupedDates: { [id: number]: GroupDate } = {}
73
58 abstract getVideosObservable (page: number): Observable<{ videos: Video[], totalVideos: number }> 74 abstract getVideosObservable (page: number): Observable<{ videos: Video[], totalVideos: number }>
59 75
60 abstract generateSyndicationList (): void 76 abstract generateSyndicationList (): void
@@ -64,6 +80,15 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
64 } 80 }
65 81
66 ngOnInit () { 82 ngOnInit () {
83 this.groupedDateLabels = {
84 [GroupDate.UNKNOWN]: null,
85 [GroupDate.TODAY]: this.i18n('Today'),
86 [GroupDate.YESTERDAY]: this.i18n('Yesterday'),
87 [GroupDate.LAST_WEEK]: this.i18n('Last week'),
88 [GroupDate.LAST_MONTH]: this.i18n('Last month'),
89 [GroupDate.OLDER]: this.i18n('Older')
90 }
91
67 // Subscribe to route changes 92 // Subscribe to route changes
68 const routeParams = this.route.snapshot.queryParams 93 const routeParams = this.route.snapshot.queryParams
69 this.loadRouteParams(routeParams) 94 this.loadRouteParams(routeParams)
@@ -113,6 +138,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
113 this.pagination.totalItems = totalVideos 138 this.pagination.totalItems = totalVideos
114 this.videos = this.videos.concat(videos) 139 this.videos = this.videos.concat(videos)
115 140
141 if (this.groupByDate) this.buildGroupedDateLabels()
142
116 this.onMoreVideos() 143 this.onMoreVideos()
117 }, 144 },
118 145
@@ -134,6 +161,59 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
134 this.videos = this.videos.filter(v => v.id !== video.id) 161 this.videos = this.videos.filter(v => v.id !== video.id)
135 } 162 }
136 163
164 buildGroupedDateLabels () {
165 let currentGroupedDate: GroupDate = GroupDate.UNKNOWN
166
167 for (const video of this.videos) {
168 const publishedDate = video.publishedAt
169
170 if (currentGroupedDate <= GroupDate.TODAY && isToday(publishedDate)) {
171 if (currentGroupedDate === GroupDate.TODAY) continue
172
173 currentGroupedDate = GroupDate.TODAY
174 this.groupedDates[ video.id ] = currentGroupedDate
175 continue
176 }
177
178 if (currentGroupedDate <= GroupDate.YESTERDAY && isYesterday(publishedDate)) {
179 if (currentGroupedDate === GroupDate.YESTERDAY) continue
180
181 currentGroupedDate = GroupDate.YESTERDAY
182 this.groupedDates[ video.id ] = currentGroupedDate
183 continue
184 }
185
186 if (currentGroupedDate <= GroupDate.LAST_WEEK && isLastWeek(publishedDate)) {
187 if (currentGroupedDate === GroupDate.LAST_WEEK) continue
188
189 currentGroupedDate = GroupDate.LAST_WEEK
190 this.groupedDates[ video.id ] = currentGroupedDate
191 continue
192 }
193
194 if (currentGroupedDate <= GroupDate.LAST_MONTH && isLastMonth(publishedDate)) {
195 if (currentGroupedDate === GroupDate.LAST_MONTH) continue
196
197 currentGroupedDate = GroupDate.LAST_MONTH
198 this.groupedDates[ video.id ] = currentGroupedDate
199 continue
200 }
201
202 if (currentGroupedDate <= GroupDate.OLDER) {
203 if (currentGroupedDate === GroupDate.OLDER) continue
204
205 currentGroupedDate = GroupDate.OLDER
206 this.groupedDates[ video.id ] = currentGroupedDate
207 }
208 }
209 }
210
211 getCurrentGroupedDateLabel (video: Video) {
212 if (this.groupByDate === false) return undefined
213
214 return this.groupedDateLabels[this.groupedDates[video.id]]
215 }
216
137 // On videos hook for children that want to do something 217 // On videos hook for children that want to do something
138 protected onMoreVideos () { /* empty */ } 218 protected onMoreVideos () { /* empty */ }
139 219
diff --git a/client/src/app/shared/video/modals/video-download.component.ts b/client/src/app/shared/video/modals/video-download.component.ts
index d6d10d29e..a07560f87 100644
--- a/client/src/app/shared/video/modals/video-download.component.ts
+++ b/client/src/app/shared/video/modals/video-download.component.ts
@@ -1,6 +1,6 @@
1import { Component, ElementRef, ViewChild } from '@angular/core' 1import { Component, ElementRef, ViewChild } from '@angular/core'
2import { VideoDetails } from '../../../shared/video/video-details.model' 2import { VideoDetails } from '../../../shared/video/video-details.model'
3import { NgbModal } from '@ng-bootstrap/ng-bootstrap' 3import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'
4import { I18n } from '@ngx-translate/i18n-polyfill' 4import { I18n } from '@ngx-translate/i18n-polyfill'
5import { Notifier } from '@app/core' 5import { Notifier } from '@app/core'
6 6
@@ -16,6 +16,7 @@ export class VideoDownloadComponent {
16 resolutionId: number | string = -1 16 resolutionId: number | string = -1
17 17
18 video: VideoDetails 18 video: VideoDetails
19 activeModal: NgbActiveModal
19 20
20 constructor ( 21 constructor (
21 private notifier: Notifier, 22 private notifier: Notifier,
@@ -26,9 +27,7 @@ export class VideoDownloadComponent {
26 show (video: VideoDetails) { 27 show (video: VideoDetails) {
27 this.video = video 28 this.video = video
28 29
29 const m = this.modalService.open(this.modal) 30 this.activeModal = this.modalService.open(this.modal)
30 m.result.then(() => this.onClose())
31 .catch(() => this.onClose())
32 31
33 this.resolutionId = this.video.files[0].resolution.id 32 this.resolutionId = this.video.files[0].resolution.id
34 } 33 }
@@ -39,6 +38,7 @@ export class VideoDownloadComponent {
39 38
40 download () { 39 download () {
41 window.location.assign(this.getLink()) 40 window.location.assign(this.getLink())
41 this.activeModal.close()
42 } 42 }
43 43
44 getLink () { 44 getLink () {
diff --git a/client/src/app/shared/video/video-details.model.ts b/client/src/app/shared/video/video-details.model.ts
index 22f024656..e4d443a06 100644
--- a/client/src/app/shared/video/video-details.model.ts
+++ b/client/src/app/shared/video/video-details.model.ts
@@ -1,5 +1,4 @@
1import { UserRight, VideoConstant, VideoDetails as VideoDetailsServerModel, VideoFile, VideoState } from '../../../../../shared' 1import { VideoConstant, VideoDetails as VideoDetailsServerModel, VideoFile, VideoState } from '../../../../../shared'
2import { AuthUser } from '../../core'
3import { Video } from '../../shared/video/video.model' 2import { Video } from '../../shared/video/video.model'
4import { Account } from '@app/shared/account/account.model' 3import { Account } from '@app/shared/account/account.model'
5import { VideoChannel } from '@app/shared/video-channel/video-channel.model' 4import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
diff --git a/client/src/app/shared/video/video-edit.model.ts b/client/src/app/shared/video/video-edit.model.ts
index 1f633d427..67d8e7711 100644
--- a/client/src/app/shared/video/video-edit.model.ts
+++ b/client/src/app/shared/video/video-edit.model.ts
@@ -85,6 +85,11 @@ export class VideoEdit implements VideoUpdate {
85 const originallyPublishedAt = new Date(values['originallyPublishedAt']) 85 const originallyPublishedAt = new Date(values['originallyPublishedAt'])
86 this.originallyPublishedAt = originallyPublishedAt.toISOString() 86 this.originallyPublishedAt = originallyPublishedAt.toISOString()
87 } 87 }
88
89 // Use the same file than the preview for the thumbnail
90 if (this.previewfile) {
91 this.thumbnailfile = this.previewfile
92 }
88 } 93 }
89 94
90 toFormPatch () { 95 toFormPatch () {
diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts
index 0cef3eb8f..6f9de9241 100644
--- a/client/src/app/shared/video/video.model.ts
+++ b/client/src/app/shared/video/video.model.ts
@@ -52,7 +52,6 @@ export class Video implements VideoServerModel {
52 52
53 account: { 53 account: {
54 id: number 54 id: number
55 uuid: string
56 name: string 55 name: string
57 displayName: string 56 displayName: string
58 url: string 57 url: string
@@ -62,7 +61,6 @@ export class Video implements VideoServerModel {
62 61
63 channel: { 62 channel: {
64 id: number 63 id: number
65 uuid: string
66 name: string 64 name: string
67 displayName: string 65 displayName: string
68 url: string 66 url: string
diff --git a/client/src/app/shared/video/videos-selection.component.ts b/client/src/app/shared/video/videos-selection.component.ts
index 955ebca9f..d69f7b70e 100644
--- a/client/src/app/shared/video/videos-selection.component.ts
+++ b/client/src/app/shared/video/videos-selection.component.ts
@@ -20,6 +20,7 @@ import { Video } from '@app/shared/video/video.model'
20import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive' 20import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive'
21import { VideoSortField } from '@app/shared/video/sort-field.type' 21import { VideoSortField } from '@app/shared/video/sort-field.type'
22import { ComponentPagination } from '@app/shared/rest/component-pagination.model' 22import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
23import { I18n } from '@ngx-translate/i18n-polyfill'
23 24
24export type SelectionType = { [ id: number ]: boolean } 25export type SelectionType = { [ id: number ]: boolean }
25 26
@@ -44,6 +45,7 @@ export class VideosSelectionComponent extends AbstractVideoList implements OnIni
44 globalButtonsTemplate: TemplateRef<any> 45 globalButtonsTemplate: TemplateRef<any>
45 46
46 constructor ( 47 constructor (
48 protected i18n: I18n,
47 protected router: Router, 49 protected router: Router,
48 protected route: ActivatedRoute, 50 protected route: ActivatedRoute,
49 protected notifier: Notifier, 51 protected notifier: Notifier,
diff --git a/client/src/app/signup/index.ts b/client/src/app/signup/index.ts
deleted file mode 100644
index b0aca9723..000000000
--- a/client/src/app/signup/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
1export * from './signup-routing.module'
2export * from './signup.component'
3export * from './signup.module'
diff --git a/client/src/app/signup/signup.component.html b/client/src/app/signup/signup.component.html
deleted file mode 100644
index 07d24b381..000000000
--- a/client/src/app/signup/signup.component.html
+++ /dev/null
@@ -1,72 +0,0 @@
1<div class="margin-content">
2
3 <div i18n class="title-page title-page-single">
4 Create an account
5 </div>
6
7 <div *ngIf="info" class="alert alert-info">{{ info }}</div>
8 <div *ngIf="error" class="alert alert-danger">{{ error }}</div>
9
10 <div class="d-flex justify-content-left flex-wrap">
11 <form role="form" (ngSubmit)="signup()" [formGroup]="form">
12 <div class="form-group">
13 <label for="username" i18n>Username</label>
14
15 <div class="input-group">
16 <input
17 type="text" id="username" i18n-placeholder placeholder="Example: jane_doe"
18 formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }"
19 >
20 <div class="input-group-append">
21 <span class="input-group-text">@{{ instanceHost }}</span>
22 </div>
23 </div>
24
25 <div *ngIf="formErrors.username" class="form-error">
26 {{ formErrors.username }}
27 </div>
28 </div>
29
30 <div class="form-group">
31 <label for="email" i18n>Email</label>
32 <input
33 type="text" id="email" i18n-placeholder placeholder="Email"
34 formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }"
35 >
36 <div *ngIf="formErrors.email" class="form-error">
37 {{ formErrors.email }}
38 </div>
39 </div>
40
41 <div class="form-group">
42 <label for="password" i18n>Password</label>
43 <input
44 type="password" id="password" i18n-placeholder placeholder="Password"
45 formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }"
46 >
47 <div *ngIf="formErrors.password" class="form-error">
48 {{ formErrors.password }}
49 </div>
50 </div>
51
52 <div class="form-group form-group-terms">
53 <my-peertube-checkbox
54 inputName="terms" formControlName="terms"
55 i18n-labelHtml labelHtml="I am at least 16 years old and agree to the <a href='/about/instance#terms-section' target='_blank'rel='noopener noreferrer'>Terms</a> of this instance"
56 ></my-peertube-checkbox>
57
58 <div *ngIf="formErrors.terms" class="form-error">
59 {{ formErrors.terms }}
60 </div>
61 </div>
62
63 <input type="submit" i18n-value value="Signup" [disabled]="!form.valid || signupDone">
64 </form>
65
66 <div>
67 <label i18n>Features found on this instance</label>
68 <my-instance-features-table></my-instance-features-table>
69 </div>
70 </div>
71
72</div>
diff --git a/client/src/app/signup/signup.component.ts b/client/src/app/signup/signup.component.ts
deleted file mode 100644
index 13941ec79..000000000
--- a/client/src/app/signup/signup.component.ts
+++ /dev/null
@@ -1,78 +0,0 @@
1import { Component, OnInit } from '@angular/core'
2import { AuthService, Notifier, RedirectService, ServerService } from '@app/core'
3import { UserCreate } from '../../../../shared'
4import { FormReactive, UserService, UserValidatorsService } from '../shared'
5import { I18n } from '@ngx-translate/i18n-polyfill'
6import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
7
8@Component({
9 selector: 'my-signup',
10 templateUrl: './signup.component.html',
11 styleUrls: [ './signup.component.scss' ]
12})
13export class SignupComponent extends FormReactive implements OnInit {
14 info: string = null
15 error: string = null
16 signupDone = false
17
18 constructor (
19 protected formValidatorService: FormValidatorService,
20 private authService: AuthService,
21 private userValidatorsService: UserValidatorsService,
22 private notifier: Notifier,
23 private userService: UserService,
24 private serverService: ServerService,
25 private redirectService: RedirectService,
26 private i18n: I18n
27 ) {
28 super()
29 }
30
31 get instanceHost () {
32 return window.location.host
33 }
34
35 get requiresEmailVerification () {
36 return this.serverService.getConfig().signup.requiresEmailVerification
37 }
38
39 ngOnInit () {
40 this.buildForm({
41 username: this.userValidatorsService.USER_USERNAME,
42 password: this.userValidatorsService.USER_PASSWORD,
43 email: this.userValidatorsService.USER_EMAIL,
44 terms: this.userValidatorsService.USER_TERMS
45 })
46 }
47
48 signup () {
49 this.error = null
50
51 const userCreate: UserCreate = this.form.value
52
53 this.userService.signup(userCreate).subscribe(
54 () => {
55 this.signupDone = true
56
57 if (this.requiresEmailVerification) {
58 this.info = this.i18n('Welcome! Now please check your emails to verify your account and complete signup.')
59 return
60 }
61
62 // Auto login
63 this.authService.login(userCreate.username, userCreate.password)
64 .subscribe(
65 () => {
66 this.notifier.success(this.i18n('You are now logged in as {{username}}!', { username: userCreate.username }))
67
68 this.redirectService.redirectToHomepage()
69 },
70
71 err => this.error = err.message
72 )
73 },
74
75 err => this.error = err.message
76 )
77 }
78}
diff --git a/client/src/app/signup/signup.module.ts b/client/src/app/signup/signup.module.ts
deleted file mode 100644
index 61560ddcf..000000000
--- a/client/src/app/signup/signup.module.ts
+++ /dev/null
@@ -1,24 +0,0 @@
1import { NgModule } from '@angular/core'
2
3import { SignupRoutingModule } from './signup-routing.module'
4import { SignupComponent } from './signup.component'
5import { SharedModule } from '../shared'
6
7@NgModule({
8 imports: [
9 SignupRoutingModule,
10 SharedModule
11 ],
12
13 declarations: [
14 SignupComponent
15 ],
16
17 exports: [
18 SignupComponent
19 ],
20
21 providers: [
22 ]
23})
24export class SignupModule { }
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.html b/client/src/app/videos/+video-edit/shared/video-edit.component.html
index 99695204d..28572d611 100644
--- a/client/src/app/videos/+video-edit/shared/video-edit.component.html
+++ b/client/src/app/videos/+video-edit/shared/video-edit.component.html
@@ -187,18 +187,14 @@
187 <ng-template ngbTabContent> 187 <ng-template ngbTabContent>
188 <div class="row advanced-settings"> 188 <div class="row advanced-settings">
189 <div class="col-md-12 col-xl-8"> 189 <div class="col-md-12 col-xl-8">
190 <div class="form-group">
191 <my-image-upload
192 i18n-inputLabel inputLabel="Upload thumbnail" inputName="thumbnailfile" formControlName="thumbnailfile"
193 previewWidth="200px" previewHeight="110px"
194 ></my-image-upload>
195 </div>
196 190
197 <div class="form-group"> 191 <div class="form-group">
198 <my-image-upload 192 <label i18n for="previewfile">Video preview</label>
199 i18n-inputLabel inputLabel="Upload preview" inputName="previewfile" formControlName="previewfile" 193
194 <my-preview-upload
195 i18n-inputLabel inputLabel="Edit" inputName="previewfile" formControlName="previewfile"
200 previewWidth="360px" previewHeight="200px" 196 previewWidth="360px" previewHeight="200px"
201 ></my-image-upload> 197 ></my-preview-upload>
202 </div> 198 </div>
203 199
204 <div class="form-group"> 200 <div class="form-group">
diff --git a/client/src/app/videos/+video-edit/shared/video-edit.component.ts b/client/src/app/videos/+video-edit/shared/video-edit.component.ts
index 8345645f6..cea352bfb 100644
--- a/client/src/app/videos/+video-edit/shared/video-edit.component.ts
+++ b/client/src/app/videos/+video-edit/shared/video-edit.component.ts
@@ -13,6 +13,7 @@ import { VideoCaptionAddModalComponent } from '@app/videos/+video-edit/shared/vi
13import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model' 13import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
14import { removeElementFromArray } from '@app/shared/misc/utils' 14import { removeElementFromArray } from '@app/shared/misc/utils'
15import { VideoConstant, VideoPrivacy } from '../../../../../../shared' 15import { VideoConstant, VideoPrivacy } from '../../../../../../shared'
16import { VideoService } from '@app/shared/video/video.service'
16 17
17@Component({ 18@Component({
18 selector: 'my-video-edit', 19 selector: 'my-video-edit',
@@ -23,7 +24,6 @@ export class VideoEditComponent implements OnInit, OnDestroy {
23 @Input() form: FormGroup 24 @Input() form: FormGroup
24 @Input() formErrors: { [ id: string ]: string } = {} 25 @Input() formErrors: { [ id: string ]: string } = {}
25 @Input() validationMessages: FormReactiveValidationMessages = {} 26 @Input() validationMessages: FormReactiveValidationMessages = {}
26 @Input() videoPrivacies: VideoConstant<VideoPrivacy>[] = []
27 @Input() userVideoChannels: { id: number, label: string, support: string }[] = [] 27 @Input() userVideoChannels: { id: number, label: string, support: string }[] = []
28 @Input() schedulePublicationPossible = true 28 @Input() schedulePublicationPossible = true
29 @Input() videoCaptions: (VideoCaptionEdit & { captionPath?: string })[] = [] 29 @Input() videoCaptions: (VideoCaptionEdit & { captionPath?: string })[] = []
@@ -34,6 +34,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
34 // So that it can be accessed in the template 34 // So that it can be accessed in the template
35 readonly SPECIAL_SCHEDULED_PRIVACY = VideoEdit.SPECIAL_SCHEDULED_PRIVACY 35 readonly SPECIAL_SCHEDULED_PRIVACY = VideoEdit.SPECIAL_SCHEDULED_PRIVACY
36 36
37 videoPrivacies: VideoConstant<VideoPrivacy>[] = []
37 videoCategories: VideoConstant<number>[] = [] 38 videoCategories: VideoConstant<number>[] = []
38 videoLicences: VideoConstant<number>[] = [] 39 videoLicences: VideoConstant<number>[] = []
39 videoLanguages: VideoConstant<string>[] = [] 40 videoLanguages: VideoConstant<string>[] = []
@@ -58,6 +59,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
58 private formValidatorService: FormValidatorService, 59 private formValidatorService: FormValidatorService,
59 private videoValidatorsService: VideoValidatorsService, 60 private videoValidatorsService: VideoValidatorsService,
60 private videoCaptionService: VideoCaptionService, 61 private videoCaptionService: VideoCaptionService,
62 private videoService: VideoService,
61 private route: ActivatedRoute, 63 private route: ActivatedRoute,
62 private router: Router, 64 private router: Router,
63 private notifier: Notifier, 65 private notifier: Notifier,
@@ -100,7 +102,6 @@ export class VideoEditComponent implements OnInit, OnDestroy {
100 language: this.videoValidatorsService.VIDEO_LANGUAGE, 102 language: this.videoValidatorsService.VIDEO_LANGUAGE,
101 description: this.videoValidatorsService.VIDEO_DESCRIPTION, 103 description: this.videoValidatorsService.VIDEO_DESCRIPTION,
102 tags: null, 104 tags: null,
103 thumbnailfile: null,
104 previewfile: null, 105 previewfile: null,
105 support: this.videoValidatorsService.VIDEO_SUPPORT, 106 support: this.videoValidatorsService.VIDEO_SUPPORT,
106 schedulePublicationAt: this.videoValidatorsService.VIDEO_SCHEDULE_PUBLICATION_AT, 107 schedulePublicationAt: this.videoValidatorsService.VIDEO_SCHEDULE_PUBLICATION_AT,
@@ -133,6 +134,9 @@ export class VideoEditComponent implements OnInit, OnDestroy {
133 this.videoLicences = this.serverService.getVideoLicences() 134 this.videoLicences = this.serverService.getVideoLicences()
134 this.videoLanguages = this.serverService.getVideoLanguages() 135 this.videoLanguages = this.serverService.getVideoLanguages()
135 136
137 const privacies = this.serverService.getVideoPrivacies()
138 this.videoPrivacies = this.videoService.explainedPrivacyLabels(privacies)
139
136 this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id) 140 this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)
137 141
138 this.ngZone.runOutsideAngular(() => { 142 this.ngZone.runOutsideAngular(() => {
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html
index 537d7ffa2..7a495fea5 100644
--- a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html
+++ b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.html
@@ -58,7 +58,7 @@
58<form [hidden]="!hasImportedVideo" novalidate [formGroup]="form"> 58<form [hidden]="!hasImportedVideo" novalidate [formGroup]="form">
59 <my-video-edit 59 <my-video-edit
60 [form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions" [schedulePublicationPossible]="false" 60 [form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions" [schedulePublicationPossible]="false"
61 [validationMessages]="validationMessages" [videoPrivacies]="explainedVideoPrivacies" [userVideoChannels]="userVideoChannels" 61 [validationMessages]="validationMessages" [userVideoChannels]="userVideoChannels"
62 ></my-video-edit> 62 ></my-video-edit>
63 63
64 <div class="submit-container"> 64 <div class="submit-container">
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts
index d2e9f6cfe..ed9cb5840 100644
--- a/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts
+++ b/client/src/app/videos/+video-edit/video-add-components/video-import-torrent.component.ts
@@ -100,7 +100,6 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
100 previewUrl: null 100 previewUrl: null
101 })) 101 }))
102 102
103 this.explainedVideoPrivacies = this.videoService.explainedPrivacyLabels(this.videoPrivacies)
104 103
105 this.hydrateFormFromVideo() 104 this.hydrateFormFromVideo()
106 }, 105 },
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html
index 984b9d590..e4f19faa8 100644
--- a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html
+++ b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.html
@@ -51,7 +51,7 @@
51<form [hidden]="!hasImportedVideo" novalidate [formGroup]="form"> 51<form [hidden]="!hasImportedVideo" novalidate [formGroup]="form">
52 <my-video-edit 52 <my-video-edit
53 [form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions" [schedulePublicationPossible]="false" 53 [form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions" [schedulePublicationPossible]="false"
54 [validationMessages]="validationMessages" [videoPrivacies]="explainedVideoPrivacies" [userVideoChannels]="userVideoChannels" 54 [validationMessages]="validationMessages" [userVideoChannels]="userVideoChannels"
55 ></my-video-edit> 55 ></my-video-edit>
56 56
57 <div class="submit-container"> 57 <div class="submit-container">
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-send.ts b/client/src/app/videos/+video-edit/video-add-components/video-send.ts
index 8401caeec..580c123a0 100644
--- a/client/src/app/videos/+video-edit/video-add-components/video-send.ts
+++ b/client/src/app/videos/+video-edit/video-add-components/video-send.ts
@@ -14,7 +14,6 @@ import { CanComponentDeactivateResult } from '@app/shared/guards/can-deactivate-
14export abstract class VideoSend extends FormReactive implements OnInit { 14export abstract class VideoSend extends FormReactive implements OnInit {
15 userVideoChannels: { id: number, label: string, support: string }[] = [] 15 userVideoChannels: { id: number, label: string, support: string }[] = []
16 videoPrivacies: VideoConstant<VideoPrivacy>[] = [] 16 videoPrivacies: VideoConstant<VideoPrivacy>[] = []
17 explainedVideoPrivacies: VideoConstant<VideoPrivacy>[] = []
18 videoCaptions: VideoCaptionEdit[] = [] 17 videoCaptions: VideoCaptionEdit[] = []
19 18
20 firstStepPrivacyId = 0 19 firstStepPrivacyId = 0
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html
index 536769d2f..0f904affb 100644
--- a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html
+++ b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html
@@ -26,6 +26,27 @@
26 </select> 26 </select>
27 </div> 27 </div>
28 </div> 28 </div>
29
30 <ng-container *ngIf="isUploadingAudioFile">
31 <div class="form-group audio-preview">
32 <label i18n for="previewfileUpload">Video background image</label>
33
34 <div i18n class="audio-image-info">
35 Image that will be merged with your audio file.
36 <br />
37 The chosen image will be definitive and cannot be modified.
38 </div>
39
40 <my-preview-upload
41 i18n-inputLabel inputLabel="Edit" inputName="previewfileUpload" [(ngModel)]="previewfileUpload"
42 previewWidth="360px" previewHeight="200px"
43 ></my-preview-upload>
44 </div>
45
46 <div class="form-group upload-audio-button">
47 <my-button className="orange-button" i18n-label [label]="getAudioUploadLabel()" icon="upload" (click)="uploadFirstStep(true)"></my-button>
48 </div>
49 </ng-container>
29 </div> 50 </div>
30</div> 51</div>
31 52
@@ -50,7 +71,7 @@
50<form [hidden]="!isUploadingVideo" novalidate [formGroup]="form"> 71<form [hidden]="!isUploadingVideo" novalidate [formGroup]="form">
51 <my-video-edit 72 <my-video-edit
52 [form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions" 73 [form]="form" [formErrors]="formErrors" [videoCaptions]="videoCaptions"
53 [validationMessages]="validationMessages" [videoPrivacies]="explainedVideoPrivacies" [userVideoChannels]="userVideoChannels" 74 [validationMessages]="validationMessages" [userVideoChannels]="userVideoChannels"
54 [waitTranscodingEnabled]="waitTranscodingEnabled" 75 [waitTranscodingEnabled]="waitTranscodingEnabled"
55 ></my-video-edit> 76 ></my-video-edit>
56 77
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.scss b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.scss
index 8adf8f169..684342f09 100644
--- a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.scss
+++ b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.scss
@@ -1,9 +1,20 @@
1@import 'variables'; 1@import 'variables';
2@import 'mixins'; 2@import 'mixins';
3 3
4.first-step-block .form-group-channel { 4.first-step-block {
5 margin-bottom: 20px; 5
6 margin-top: 35px; 6 .form-group-channel {
7 margin-bottom: 20px;
8 margin-top: 35px;
9 }
10
11 .audio-image-info {
12 margin-bottom: 10px;
13 }
14
15 .audio-preview {
16 margin: 30px 0;
17 }
7} 18}
8 19
9.upload-progress-cancel { 20.upload-progress-cancel {
diff --git a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts
index d6d4bad21..69fa13a2f 100644
--- a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts
+++ b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.ts
@@ -35,8 +35,10 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
35 userVideoQuotaUsed = 0 35 userVideoQuotaUsed = 0
36 userVideoQuotaUsedDaily = 0 36 userVideoQuotaUsedDaily = 0
37 37
38 isUploadingAudioFile = false
38 isUploadingVideo = false 39 isUploadingVideo = false
39 isUpdatingVideo = false 40 isUpdatingVideo = false
41
40 videoUploaded = false 42 videoUploaded = false
41 videoUploadObservable: Subscription = null 43 videoUploadObservable: Subscription = null
42 videoUploadPercents = 0 44 videoUploadPercents = 0
@@ -44,7 +46,9 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
44 id: 0, 46 id: 0,
45 uuid: '' 47 uuid: ''
46 } 48 }
49
47 waitTranscodingEnabled = true 50 waitTranscodingEnabled = true
51 previewfileUpload: File
48 52
49 error: string 53 error: string
50 54
@@ -100,6 +104,17 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
100 } 104 }
101 } 105 }
102 106
107 getVideoFile () {
108 return this.videofileInput.nativeElement.files[0]
109 }
110
111 getAudioUploadLabel () {
112 const videofile = this.getVideoFile()
113 if (!videofile) return this.i18n('Upload')
114
115 return this.i18n('Upload {{videofileName}}', { videofileName: videofile.name })
116 }
117
103 fileChange () { 118 fileChange () {
104 this.uploadFirstStep() 119 this.uploadFirstStep()
105 } 120 }
@@ -114,38 +129,15 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
114 } 129 }
115 } 130 }
116 131
117 uploadFirstStep () { 132 uploadFirstStep (clickedOnButton = false) {
118 const videofile = this.videofileInput.nativeElement.files[0] 133 const videofile = this.getVideoFile()
119 if (!videofile) return 134 if (!videofile) return
120 135
121 // Check global user quota 136 if (!this.checkGlobalUserQuota(videofile)) return
122 const bytePipes = new BytesPipe() 137 if (!this.checkDailyUserQuota(videofile)) return
123 const videoQuota = this.authService.getUser().videoQuota
124 if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) {
125 const msg = this.i18n(
126 'Your video quota is exceeded with this video (video size: {{videoSize}}, used: {{videoQuotaUsed}}, quota: {{videoQuota}})',
127 {
128 videoSize: bytePipes.transform(videofile.size, 0),
129 videoQuotaUsed: bytePipes.transform(this.userVideoQuotaUsed, 0),
130 videoQuota: bytePipes.transform(videoQuota, 0)
131 }
132 )
133 this.notifier.error(msg)
134 return
135 }
136 138
137 // Check daily user quota 139 if (clickedOnButton === false && this.isAudioFile(videofile.name)) {
138 const videoQuotaDaily = this.authService.getUser().videoQuotaDaily 140 this.isUploadingAudioFile = true
139 if (videoQuotaDaily !== -1 && (this.userVideoQuotaUsedDaily + videofile.size) > videoQuotaDaily) {
140 const msg = this.i18n(
141 'Your daily video quota is exceeded with this video (video size: {{videoSize}}, used: {{quotaUsedDaily}}, quota: {{quotaDaily}})',
142 {
143 videoSize: bytePipes.transform(videofile.size, 0),
144 quotaUsedDaily: bytePipes.transform(this.userVideoQuotaUsedDaily, 0),
145 quotaDaily: bytePipes.transform(videoQuotaDaily, 0)
146 }
147 )
148 this.notifier.error(msg)
149 return 141 return
150 } 142 }
151 143
@@ -180,6 +172,11 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
180 formData.append('channelId', '' + channelId) 172 formData.append('channelId', '' + channelId)
181 formData.append('videofile', videofile) 173 formData.append('videofile', videofile)
182 174
175 if (this.previewfileUpload) {
176 formData.append('previewfile', this.previewfileUpload)
177 formData.append('thumbnailfile', this.previewfileUpload)
178 }
179
183 this.isUploadingVideo = true 180 this.isUploadingVideo = true
184 this.firstStepDone.emit(name) 181 this.firstStepDone.emit(name)
185 182
@@ -187,11 +184,10 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
187 name, 184 name,
188 privacy, 185 privacy,
189 nsfw, 186 nsfw,
190 channelId 187 channelId,
188 previewfile: this.previewfileUpload
191 }) 189 })
192 190
193 this.explainedVideoPrivacies = this.videoService.explainedPrivacyLabels(this.videoPrivacies)
194
195 this.videoUploadObservable = this.videoService.uploadVideo(formData).subscribe( 191 this.videoUploadObservable = this.videoService.uploadVideo(formData).subscribe(
196 event => { 192 event => {
197 if (event.type === HttpEventType.UploadProgress) { 193 if (event.type === HttpEventType.UploadProgress) {
@@ -251,4 +247,52 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
251 } 247 }
252 ) 248 )
253 } 249 }
250
251 private checkGlobalUserQuota (videofile: File) {
252 const bytePipes = new BytesPipe()
253
254 // Check global user quota
255 const videoQuota = this.authService.getUser().videoQuota
256 if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) {
257 const msg = this.i18n(
258 'Your video quota is exceeded with this video (video size: {{videoSize}}, used: {{videoQuotaUsed}}, quota: {{videoQuota}})',
259 {
260 videoSize: bytePipes.transform(videofile.size, 0),
261 videoQuotaUsed: bytePipes.transform(this.userVideoQuotaUsed, 0),
262 videoQuota: bytePipes.transform(videoQuota, 0)
263 }
264 )
265 this.notifier.error(msg)
266
267 return false
268 }
269
270 return true
271 }
272
273 private checkDailyUserQuota (videofile: File) {
274 const bytePipes = new BytesPipe()
275
276 // Check daily user quota
277 const videoQuotaDaily = this.authService.getUser().videoQuotaDaily
278 if (videoQuotaDaily !== -1 && (this.userVideoQuotaUsedDaily + videofile.size) > videoQuotaDaily) {
279 const msg = this.i18n(
280 'Your daily video quota is exceeded with this video (video size: {{videoSize}}, used: {{quotaUsedDaily}}, quota: {{quotaDaily}})',
281 {
282 videoSize: bytePipes.transform(videofile.size, 0),
283 quotaUsedDaily: bytePipes.transform(this.userVideoQuotaUsedDaily, 0),
284 quotaDaily: bytePipes.transform(videoQuotaDaily, 0)
285 }
286 )
287 this.notifier.error(msg)
288
289 return false
290 }
291
292 return true
293 }
294
295 private isAudioFile (filename: string) {
296 return filename.endsWith('.mp3') || filename.endsWith('.flac') || filename.endsWith('.ogg')
297 }
254} 298}
diff --git a/client/src/app/videos/+video-edit/video-update.component.html b/client/src/app/videos/+video-edit/video-update.component.html
index b5cab7ed5..aa148311f 100644
--- a/client/src/app/videos/+video-edit/video-update.component.html
+++ b/client/src/app/videos/+video-edit/video-update.component.html
@@ -7,7 +7,7 @@
7 7
8 <my-video-edit 8 <my-video-edit
9 [form]="form" [formErrors]="formErrors" [schedulePublicationPossible]="schedulePublicationPossible" 9 [form]="form" [formErrors]="formErrors" [schedulePublicationPossible]="schedulePublicationPossible"
10 [validationMessages]="validationMessages" [videoPrivacies]="explainedVideoPrivacies" [userVideoChannels]="userVideoChannels" 10 [validationMessages]="validationMessages" [userVideoChannels]="userVideoChannels"
11 [videoCaptions]="videoCaptions" [waitTranscodingEnabled]="waitTranscodingEnabled" 11 [videoCaptions]="videoCaptions" [waitTranscodingEnabled]="waitTranscodingEnabled"
12 ></my-video-edit> 12 ></my-video-edit>
13 13
diff --git a/client/src/app/videos/+video-edit/video-update.component.ts b/client/src/app/videos/+video-edit/video-update.component.ts
index 10f797d02..e990ceb13 100644
--- a/client/src/app/videos/+video-edit/video-update.component.ts
+++ b/client/src/app/videos/+video-edit/video-update.component.ts
@@ -3,7 +3,6 @@ import { Component, HostListener, OnInit } from '@angular/core'
3import { ActivatedRoute, Router } from '@angular/router' 3import { ActivatedRoute, Router } from '@angular/router'
4import { LoadingBarService } from '@ngx-loading-bar/core' 4import { LoadingBarService } from '@ngx-loading-bar/core'
5import { Notifier } from '@app/core' 5import { Notifier } from '@app/core'
6import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos'
7import { ServerService } from '../../core' 6import { ServerService } from '../../core'
8import { FormReactive } from '../../shared' 7import { FormReactive } from '../../shared'
9import { VideoEdit } from '../../shared/video/video-edit.model' 8import { VideoEdit } from '../../shared/video/video-edit.model'
@@ -23,8 +22,6 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
23 video: VideoEdit 22 video: VideoEdit
24 23
25 isUpdatingVideo = false 24 isUpdatingVideo = false
26 videoPrivacies: VideoConstant<VideoPrivacy>[] = []
27 explainedVideoPrivacies: VideoConstant<VideoPrivacy>[] = []
28 userVideoChannels: { id: number, label: string, support: string }[] = [] 25 userVideoChannels: { id: number, label: string, support: string }[] = []
29 schedulePublicationPossible = false 26 schedulePublicationPossible = false
30 videoCaptions: VideoCaptionEdit[] = [] 27 videoCaptions: VideoCaptionEdit[] = []
@@ -49,9 +46,6 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
49 ngOnInit () { 46 ngOnInit () {
50 this.buildForm({}) 47 this.buildForm({})
51 48
52 this.serverService.videoPrivaciesLoaded
53 .subscribe(() => this.videoPrivacies = this.serverService.getVideoPrivacies())
54
55 this.route.data 49 this.route.data
56 .pipe(map(data => data.videoData)) 50 .pipe(map(data => data.videoData))
57 .subscribe(({ video, videoChannels, videoCaptions }) => { 51 .subscribe(({ video, videoChannels, videoCaptions }) => {
@@ -59,15 +53,6 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
59 this.userVideoChannels = videoChannels 53 this.userVideoChannels = videoChannels
60 this.videoCaptions = videoCaptions 54 this.videoCaptions = videoCaptions
61 55
62 // We cannot set private a video that was not private
63 if (this.video.privacy !== VideoPrivacy.PRIVATE) {
64 this.videoPrivacies = this.videoPrivacies.filter(p => p.id !== VideoPrivacy.PRIVATE)
65 } else { // We can schedule video publication only if it it is private
66 this.schedulePublicationPossible = this.video.privacy === VideoPrivacy.PRIVATE
67 }
68
69 this.explainedVideoPrivacies = this.videoService.explainedPrivacyLabels(this.videoPrivacies)
70
71 const videoFiles = (video as VideoDetails).files 56 const videoFiles = (video as VideoDetails).files
72 if (videoFiles.length > 1) { // Already transcoded 57 if (videoFiles.length > 1) { // Already transcoded
73 this.waitTranscodingEnabled = false 58 this.waitTranscodingEnabled = false
diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts
index 631504eab..2d13f1b58 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -6,7 +6,7 @@ import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
6import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' 6import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component'
7import { MetaService } from '@ngx-meta/core' 7import { MetaService } from '@ngx-meta/core'
8import { Notifier, ServerService } from '@app/core' 8import { Notifier, ServerService } from '@app/core'
9import { forkJoin, Subscription } from 'rxjs' 9import { forkJoin, Observable, Subscription } from 'rxjs'
10import { Hotkey, HotkeysService } from 'angular2-hotkeys' 10import { Hotkey, HotkeysService } from 'angular2-hotkeys'
11import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared' 11import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared'
12import { AuthService, ConfirmService } from '../../core' 12import { AuthService, ConfirmService } from '../../core'
@@ -135,22 +135,18 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
135 135
136 setLike () { 136 setLike () {
137 if (this.isUserLoggedIn() === false) return 137 if (this.isUserLoggedIn() === false) return
138 if (this.userRating === 'like') { 138
139 // Already liked this video 139 // Already liked this video
140 this.setRating('none') 140 if (this.userRating === 'like') this.setRating('none')
141 } else { 141 else this.setRating('like')
142 this.setRating('like')
143 }
144 } 142 }
145 143
146 setDislike () { 144 setDislike () {
147 if (this.isUserLoggedIn() === false) return 145 if (this.isUserLoggedIn() === false) return
148 if (this.userRating === 'dislike') { 146
149 // Already disliked this video 147 // Already disliked this video
150 this.setRating('none') 148 if (this.userRating === 'dislike') this.setRating('none')
151 } else { 149 else this.setRating('dislike')
152 this.setRating('dislike')
153 }
154 } 150 }
155 151
156 showMoreDescription () { 152 showMoreDescription () {
@@ -249,12 +245,15 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
249 ) 245 )
250 .subscribe(([ video, captionsResult ]) => { 246 .subscribe(([ video, captionsResult ]) => {
251 const queryParams = this.route.snapshot.queryParams 247 const queryParams = this.route.snapshot.queryParams
252 const startTime = queryParams.start
253 const stopTime = queryParams.stop
254 const subtitle = queryParams.subtitle
255 const playerMode = queryParams.mode
256 248
257 this.onVideoFetched(video, captionsResult.data, { startTime, stopTime, subtitle, playerMode }) 249 const urlOptions = {
250 startTime: queryParams.start,
251 stopTime: queryParams.stop,
252 subtitle: queryParams.subtitle,
253 playerMode: queryParams.mode
254 }
255
256 this.onVideoFetched(video, captionsResult.data, urlOptions)
258 .catch(err => this.handleError(err)) 257 .catch(err => this.handleError(err))
259 }) 258 })
260 } 259 }
@@ -279,6 +278,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
279 private updateVideoDescription (description: string) { 278 private updateVideoDescription (description: string) {
280 this.video.description = description 279 this.video.description = description
281 this.setVideoDescriptionHTML() 280 this.setVideoDescriptionHTML()
281 .catch(err => console.error(err))
282 } 282 }
283 283
284 private async setVideoDescriptionHTML () { 284 private async setVideoDescriptionHTML () {
@@ -385,7 +385,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
385 captions: videoCaptions.length !== 0, 385 captions: videoCaptions.length !== 0,
386 peertubeLink: false, 386 peertubeLink: false,
387 387
388 videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE ? this.videoService.getVideoViewUrl(this.video.uuid) : null, 388 videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE
389 ? this.videoService.getVideoViewUrl(this.video.uuid)
390 : null,
389 embedUrl: this.video.embedUrl, 391 embedUrl: this.video.embedUrl,
390 392
391 language: this.localeId, 393 language: this.localeId,
@@ -466,20 +468,13 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
466 } 468 }
467 469
468 private setRating (nextRating: UserVideoRateType) { 470 private setRating (nextRating: UserVideoRateType) {
469 let method 471 const ratingMethods: { [id in UserVideoRateType]: (id: number) => Observable<any> } = {
470 switch (nextRating) { 472 like: this.videoService.setVideoLike,
471 case 'like': 473 dislike: this.videoService.setVideoDislike,
472 method = this.videoService.setVideoLike 474 none: this.videoService.unsetVideoLike
473 break
474 case 'dislike':
475 method = this.videoService.setVideoDislike
476 break
477 case 'none':
478 method = this.videoService.unsetVideoLike
479 break
480 } 475 }
481 476
482 method.call(this.videoService, this.video.id) 477 ratingMethods[nextRating].call(this.videoService, this.video.id)
483 .subscribe( 478 .subscribe(
484 () => { 479 () => {
485 // Update the video like attribute 480 // Update the video like attribute
@@ -545,25 +540,29 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
545 private flushPlayer () { 540 private flushPlayer () {
546 // Remove player if it exists 541 // Remove player if it exists
547 if (this.player) { 542 if (this.player) {
548 this.player.dispose() 543 try {
549 this.player = undefined 544 this.player.dispose()
545 this.player = undefined
546 } catch (err) {
547 console.error('Cannot dispose player.', err)
548 }
550 } 549 }
551 } 550 }
552 551
553 private initHotkeys () { 552 private initHotkeys () {
554 this.hotkeys = [ 553 this.hotkeys = [
555 new Hotkey('shift+l', (event: KeyboardEvent): boolean => { 554 new Hotkey('shift+l', () => {
556 this.setLike() 555 this.setLike()
557 return false 556 return false
558 }, undefined, this.i18n('Like the video')), 557 }, undefined, this.i18n('Like the video')),
559 new Hotkey('shift+d', (event: KeyboardEvent): boolean => { 558
559 new Hotkey('shift+d', () => {
560 this.setDislike() 560 this.setDislike()
561 return false 561 return false
562 }, undefined, this.i18n('Dislike the video')), 562 }, undefined, this.i18n('Dislike the video')),
563 new Hotkey('shift+s', (event: KeyboardEvent): boolean => { 563
564 this.subscribeButton.subscribed ? 564 new Hotkey('shift+s', () => {
565 this.subscribeButton.unsubscribe() : 565 this.subscribeButton.subscribed ? this.subscribeButton.unsubscribe() : this.subscribeButton.subscribe()
566 this.subscribeButton.subscribe()
567 return false 566 return false
568 }, undefined, this.i18n('Subscribe to the account')) 567 }, undefined, this.i18n('Subscribe to the account'))
569 ] 568 ]
diff --git a/client/src/app/videos/video-list/video-local.component.ts b/client/src/app/videos/video-list/video-local.component.ts
index 13d4023c2..65543343c 100644
--- a/client/src/app/videos/video-list/video-local.component.ts
+++ b/client/src/app/videos/video-list/video-local.component.ts
@@ -22,13 +22,13 @@ export class VideoLocalComponent extends AbstractVideoList implements OnInit, On
22 filter: VideoFilter = 'local' 22 filter: VideoFilter = 'local'
23 23
24 constructor ( 24 constructor (
25 protected i18n: I18n,
25 protected router: Router, 26 protected router: Router,
26 protected serverService: ServerService, 27 protected serverService: ServerService,
27 protected route: ActivatedRoute, 28 protected route: ActivatedRoute,
28 protected notifier: Notifier, 29 protected notifier: Notifier,
29 protected authService: AuthService, 30 protected authService: AuthService,
30 protected screenService: ScreenService, 31 protected screenService: ScreenService,
31 private i18n: I18n,
32 private videoService: VideoService 32 private videoService: VideoService
33 ) { 33 ) {
34 super() 34 super()
diff --git a/client/src/app/videos/video-list/video-overview.component.html b/client/src/app/videos/video-list/video-overview.component.html
index b644dd798..f59de584a 100644
--- a/client/src/app/videos/video-list/video-overview.component.html
+++ b/client/src/app/videos/video-list/video-overview.component.html
@@ -3,7 +3,7 @@
3 <div class="no-results" i18n *ngIf="notResults">No results.</div> 3 <div class="no-results" i18n *ngIf="notResults">No results.</div>
4 4
5 <div class="section" *ngFor="let object of overview.categories"> 5 <div class="section" *ngFor="let object of overview.categories">
6 <div class="section-title" i18n> 6 <div class="section-title">
7 <a routerLink="/search" [queryParams]="{ categoryOneOf: [ object.category.id ] }">{{ object.category.label }}</a> 7 <a routerLink="/search" [queryParams]="{ categoryOneOf: [ object.category.id ] }">{{ object.category.label }}</a>
8 </div> 8 </div>
9 9
@@ -11,7 +11,7 @@
11 </div> 11 </div>
12 12
13 <div class="section" *ngFor="let object of overview.tags"> 13 <div class="section" *ngFor="let object of overview.tags">
14 <div class="section-title" i18n> 14 <div class="section-title">
15 <a routerLink="/search" [queryParams]="{ tagsOneOf: [ object.tag ] }">#{{ object.tag }}</a> 15 <a routerLink="/search" [queryParams]="{ tagsOneOf: [ object.tag ] }">#{{ object.tag }}</a>
16 </div> 16 </div>
17 17
@@ -19,7 +19,7 @@
19 </div> 19 </div>
20 20
21 <div class="section channel" *ngFor="let object of overview.channels"> 21 <div class="section channel" *ngFor="let object of overview.channels">
22 <div class="section-title" i18n> 22 <div class="section-title">
23 <a [routerLink]="[ '/video-channels', buildVideoChannelBy(object) ]"> 23 <a [routerLink]="[ '/video-channels', buildVideoChannelBy(object) ]">
24 <img [src]="buildVideoChannelAvatarUrl(object)" alt="Avatar" /> 24 <img [src]="buildVideoChannelAvatarUrl(object)" alt="Avatar" />
25 25
diff --git a/client/src/app/videos/video-list/video-overview.component.scss b/client/src/app/videos/video-list/video-overview.component.scss
index a24766783..ade6f53b7 100644
--- a/client/src/app/videos/video-list/video-overview.component.scss
+++ b/client/src/app/videos/video-list/video-overview.component.scss
@@ -2,62 +2,10 @@
2@import '_mixins'; 2@import '_mixins';
3@import '_miniature'; 3@import '_miniature';
4 4
5.section { 5.margin-content {
6 max-height: 500px; // 2 rows max 6 @include adapt-margin-content-width;
7 overflow: hidden;
8 padding-top: 10px;
9
10 &:first-child {
11 padding-top: 30px;
12 }
13
14 my-video-miniature {
15 text-align: left;
16 }
17}
18
19.section-title {
20 font-size: 24px;
21 font-weight: $font-semibold;
22 margin-bottom: 10px;
23
24 a {
25 &:hover, &:focus:not(.focus-visible), &:active {
26 text-decoration: none;
27 outline: none;
28 }
29
30 color: var(--mainForegroundColor);
31 }
32} 7}
33 8
34.channel { 9.section {
35 .section-title a { 10 @include miniature-rows;
36 display: flex;
37 width: fit-content;
38 align-items: center;
39
40 img {
41 @include avatar(28px);
42
43 margin-right: 8px;
44 }
45 }
46}
47
48@media screen and (max-width: 500px) {
49 .margin-content {
50 margin: 0 !important;
51 }
52
53 .section-title {
54 font-size: 17px;
55 }
56
57 .section {
58 max-height: initial;
59 overflow: initial;
60
61 @include video-miniature-small-screen;
62 }
63} 11}
diff --git a/client/src/app/videos/video-list/video-recently-added.component.ts b/client/src/app/videos/video-list/video-recently-added.component.ts
index 80cef813e..f54bade98 100644
--- a/client/src/app/videos/video-list/video-recently-added.component.ts
+++ b/client/src/app/videos/video-list/video-recently-added.component.ts
@@ -17,15 +17,16 @@ import { Notifier, ServerService } from '@app/core'
17export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy { 17export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy {
18 titlePage: string 18 titlePage: string
19 sort: VideoSortField = '-publishedAt' 19 sort: VideoSortField = '-publishedAt'
20 groupByDate = true
20 21
21 constructor ( 22 constructor (
23 protected i18n: I18n,
22 protected route: ActivatedRoute, 24 protected route: ActivatedRoute,
23 protected serverService: ServerService, 25 protected serverService: ServerService,
24 protected router: Router, 26 protected router: Router,
25 protected notifier: Notifier, 27 protected notifier: Notifier,
26 protected authService: AuthService, 28 protected authService: AuthService,
27 protected screenService: ScreenService, 29 protected screenService: ScreenService,
28 private i18n: I18n,
29 private videoService: VideoService 30 private videoService: VideoService
30 ) { 31 ) {
31 super() 32 super()
diff --git a/client/src/app/videos/video-list/video-trending.component.ts b/client/src/app/videos/video-list/video-trending.component.ts
index e2ad95bc4..a2c819ebe 100644
--- a/client/src/app/videos/video-list/video-trending.component.ts
+++ b/client/src/app/videos/video-list/video-trending.component.ts
@@ -19,13 +19,13 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit,
19 defaultSort: VideoSortField = '-trending' 19 defaultSort: VideoSortField = '-trending'
20 20
21 constructor ( 21 constructor (
22 protected i18n: I18n,
22 protected router: Router, 23 protected router: Router,
23 protected serverService: ServerService, 24 protected serverService: ServerService,
24 protected route: ActivatedRoute, 25 protected route: ActivatedRoute,
25 protected notifier: Notifier, 26 protected notifier: Notifier,
26 protected authService: AuthService, 27 protected authService: AuthService,
27 protected screenService: ScreenService, 28 protected screenService: ScreenService,
28 private i18n: I18n,
29 private videoService: VideoService 29 private videoService: VideoService
30 ) { 30 ) {
31 super() 31 super()
diff --git a/client/src/app/videos/video-list/video-user-subscriptions.component.ts b/client/src/app/videos/video-list/video-user-subscriptions.component.ts
index 2f0685ccc..3caa371d8 100644
--- a/client/src/app/videos/video-list/video-user-subscriptions.component.ts
+++ b/client/src/app/videos/video-list/video-user-subscriptions.component.ts
@@ -19,15 +19,16 @@ export class VideoUserSubscriptionsComponent extends AbstractVideoList implement
19 titlePage: string 19 titlePage: string
20 sort = '-publishedAt' as VideoSortField 20 sort = '-publishedAt' as VideoSortField
21 ownerDisplayType: OwnerDisplayType = 'auto' 21 ownerDisplayType: OwnerDisplayType = 'auto'
22 groupByDate = true
22 23
23 constructor ( 24 constructor (
25 protected i18n: I18n,
24 protected router: Router, 26 protected router: Router,
25 protected serverService: ServerService, 27 protected serverService: ServerService,
26 protected route: ActivatedRoute, 28 protected route: ActivatedRoute,
27 protected notifier: Notifier, 29 protected notifier: Notifier,
28 protected authService: AuthService, 30 protected authService: AuthService,
29 protected screenService: ScreenService, 31 protected screenService: ScreenService,
30 private i18n: I18n,
31 private videoService: VideoService 32 private videoService: VideoService
32 ) { 33 ) {
33 super() 34 super()
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts
index 6cdd54372..31cbc7dfd 100644
--- a/client/src/assets/player/peertube-player-manager.ts
+++ b/client/src/assets/player/peertube-player-manager.ts
@@ -117,8 +117,17 @@ export class PeertubePlayerManager {
117 videojs(options.common.playerElement, videojsOptions, function (this: any) { 117 videojs(options.common.playerElement, videojsOptions, function (this: any) {
118 const player = this 118 const player = this
119 119
120 player.tech_.one('error', () => self.maybeFallbackToWebTorrent(mode, player, options)) 120 let alreadyFallback = false
121 player.one('error', () => self.maybeFallbackToWebTorrent(mode, player, options)) 121
122 player.tech_.one('error', () => {
123 if (!alreadyFallback) self.maybeFallbackToWebTorrent(mode, player, options)
124 alreadyFallback = true
125 })
126
127 player.one('error', () => {
128 if (!alreadyFallback) self.maybeFallbackToWebTorrent(mode, player, options)
129 alreadyFallback = true
130 })
122 131
123 self.addContextMenu(mode, player, options.common.embedUrl) 132 self.addContextMenu(mode, player, options.common.embedUrl)
124 133
diff --git a/client/src/sass/include/_miniature.scss b/client/src/sass/include/_miniature.scss
index b62187fd2..0c2ee2d0d 100644
--- a/client/src/sass/include/_miniature.scss
+++ b/client/src/sass/include/_miniature.scss
@@ -138,3 +138,100 @@ $play-overlay-width: 18px;
138 } 138 }
139 } 139 }
140} 140}
141
142@mixin miniature-rows {
143 max-height: 540px; // 2 rows max
144 overflow: hidden;
145 padding-top: 10px;
146
147 &:first-child {
148 padding-top: 30px;
149 }
150
151 my-video-miniature {
152 text-align: left;
153 }
154
155 .section-title {
156 font-size: 24px;
157 font-weight: $font-semibold;
158 margin-bottom: 30px;
159 display: flex;
160 justify-content: space-between;
161
162 a {
163 &:hover, &:focus:not(.focus-visible), &:active {
164 text-decoration: none;
165 outline: none;
166 }
167
168 color: var(--mainForegroundColor);
169 }
170 }
171
172 &.channel {
173 .section-title {
174 a {
175 display: flex;
176 width: fit-content;
177 align-items: center;
178
179 img {
180 @include avatar(28px);
181
182 margin-right: 8px;
183 }
184 }
185
186 .followers {
187 color: $grey-foreground-color;
188 font-weight: normal;
189 font-size: 14px;
190 margin-left: 10px;
191 position: relative;
192 top: 2px;
193 }
194 }
195 }
196
197 @media screen and (max-width: $mobile-view) {
198 max-height: initial;
199 overflow: initial;
200
201 @include video-miniature-small-screen;
202
203 .section-title {
204 font-size: 17px;
205 }
206 }
207}
208
209@mixin adapt-margin-content-width {
210 width: $video-miniature-width * 6;
211 margin: auto !important;
212
213 @media screen and (max-width: 1800px) {
214 width: $video-miniature-width * 5;
215 }
216
217 @media screen and (max-width: 1800px - $video-miniature-width) {
218 width: $video-miniature-width * 4;
219 }
220
221 @media screen and (max-width: 1800px - (2* $video-miniature-width)) {
222 width: $video-miniature-width * 3;
223 }
224
225 @media screen and (max-width: 1800px - (3* $video-miniature-width)) {
226 width: $video-miniature-width * 2;
227 }
228
229 @media screen and (max-width: 500px) {
230 width: auto;
231 margin: 0 !important;
232
233 .videos {
234 @include video-miniature-small-screen;
235 }
236 }
237}
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss
index 262a8136f..d4a2269a1 100644
--- a/client/src/sass/include/_mixins.scss
+++ b/client/src/sass/include/_mixins.scss
@@ -331,7 +331,12 @@
331} 331}
332 332
333@mixin peertube-checkbox ($border-width) { 333@mixin peertube-checkbox ($border-width) {
334 display: none; 334 opacity: 0;
335 position: absolute;
336
337 &:focus + span {
338 outline: 1px solid #1e5180;
339 }
335 340
336 & + span { 341 & + span {
337 position: relative; 342 position: relative;
diff --git a/config/default.yaml b/config/default.yaml
index 37ef4366f..e4e2d2273 100644
--- a/config/default.yaml
+++ b/config/default.yaml
@@ -53,6 +53,12 @@ smtp:
53 ca_file: null # Used for self signed certificates 53 ca_file: null # Used for self signed certificates
54 from_address: 'admin@example.com' 54 from_address: 'admin@example.com'
55 55
56email:
57 body:
58 signature: "PeerTube"
59 object:
60 prefix: "[PeerTube]"
61
56# From the project root directory 62# From the project root directory
57storage: 63storage:
58 tmp: 'storage/tmp/' # Used to download data (imports etc), store uploaded files before processing... 64 tmp: 'storage/tmp/' # Used to download data (imports etc), store uploaded files before processing...
@@ -174,6 +180,8 @@ transcoding:
174 enabled: true 180 enabled: true
175 # Allow your users to upload .mkv, .mov, .avi, .flv videos 181 # Allow your users to upload .mkv, .mov, .avi, .flv videos
176 allow_additional_extensions: true 182 allow_additional_extensions: true
183 # If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file
184 allow_audio_files: true
177 threads: 1 185 threads: 1
178 resolutions: # Only created if the original video has a higher resolution, uses more storage! 186 resolutions: # Only created if the original video has a higher resolution, uses more storage!
179 240p: false 187 240p: false
@@ -181,6 +189,7 @@ transcoding:
181 480p: false 189 480p: false
182 720p: false 190 720p: false
183 1080p: false 191 1080p: false
192 2160p: false
184 # /!\ EXPERIMENTAL /!\ 193 # /!\ EXPERIMENTAL /!\
185 # /!\ Requires ffmpeg >= 4 194 # /!\ Requires ffmpeg >= 4
186 # Generate HLS playlists and fragmented MP4 files. Better playback than with WebTorrent: 195 # Generate HLS playlists and fragmented MP4 files. Better playback than with WebTorrent:
diff --git a/config/production.yaml.example b/config/production.yaml.example
index f84e15670..c025426bb 100644
--- a/config/production.yaml.example
+++ b/config/production.yaml.example
@@ -188,6 +188,8 @@ transcoding:
188 enabled: true 188 enabled: true
189 # Allow your users to upload .mkv, .mov, .avi, .flv videos 189 # Allow your users to upload .mkv, .mov, .avi, .flv videos
190 allow_additional_extensions: true 190 allow_additional_extensions: true
191 # If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file
192 allow_audio_files: true
191 threads: 1 193 threads: 1
192 resolutions: # Only created if the original video has a higher resolution, uses more storage! 194 resolutions: # Only created if the original video has a higher resolution, uses more storage!
193 240p: false 195 240p: false
@@ -195,6 +197,7 @@ transcoding:
195 480p: false 197 480p: false
196 720p: false 198 720p: false
197 1080p: false 199 1080p: false
200 2160p: false
198 # /!\ EXPERIMENTAL /!\ 201 # /!\ EXPERIMENTAL /!\
199 # /!\ Requires ffmpeg >= 4 202 # /!\ Requires ffmpeg >= 4
200 # Generate HLS playlists and fragmented MP4 files. Better playback than with WebTorrent: 203 # Generate HLS playlists and fragmented MP4 files. Better playback than with WebTorrent:
diff --git a/config/test-2.yaml b/config/test-2.yaml
index a5515afa4..de7300366 100644
--- a/config/test-2.yaml
+++ b/config/test-2.yaml
@@ -31,3 +31,4 @@ signup:
31transcoding: 31transcoding:
32 enabled: true 32 enabled: true
33 allow_additional_extensions: true 33 allow_additional_extensions: true
34 allow_audio_files: true
diff --git a/config/test.yaml b/config/test.yaml
index 682530840..8d3921614 100644
--- a/config/test.yaml
+++ b/config/test.yaml
@@ -55,6 +55,7 @@ signup:
55transcoding: 55transcoding:
56 enabled: true 56 enabled: true
57 allow_additional_extensions: false 57 allow_additional_extensions: false
58 allow_audio_files: false
58 threads: 2 59 threads: 2
59 resolutions: 60 resolutions:
60 240p: true 61 240p: true
@@ -62,6 +63,7 @@ transcoding:
62 480p: true 63 480p: true
63 720p: true 64 720p: true
64 1080p: true 65 1080p: true
66 2160p: true
65 hls: 67 hls:
66 enabled: true 68 enabled: true
67 69
diff --git a/package.json b/package.json
index bea949796..6597b055e 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
23 "scripts": { 23 "scripts": {
24 "e2e": "scripty", 24 "e2e": "scripty",
25 "e2e:local": "scripty", 25 "e2e:local": "scripty",
26 "setup:cli": "scripty",
26 "build": "SCRIPTY_PARALLEL=true scripty", 27 "build": "SCRIPTY_PARALLEL=true scripty",
27 "build:server": "scripty", 28 "build:server": "scripty",
28 "build:client": "scripty", 29 "build:client": "scripty",
@@ -92,10 +93,9 @@
92 }, 93 },
93 "dependencies": { 94 "dependencies": {
94 "apicache": "^1.4.0", 95 "apicache": "^1.4.0",
95 "application-config": "^1.0.1", 96 "async": "^3.0.1",
96 "async": "^2.0.0",
97 "async-lru": "^1.1.1", 97 "async-lru": "^1.1.1",
98 "bcrypt": "3.0.5", 98 "bcrypt": "3.0.6",
99 "bittorrent-tracker": "^9.0.0", 99 "bittorrent-tracker": "^9.0.0",
100 "bluebird": "^3.5.0", 100 "bluebird": "^3.5.0",
101 "body-parser": "^1.12.4", 101 "body-parser": "^1.12.4",
@@ -103,7 +103,6 @@
103 "bytes": "^3.0.0", 103 "bytes": "^3.0.0",
104 "cli-table": "^0.3.1", 104 "cli-table": "^0.3.1",
105 "commander": "^2.13.0", 105 "commander": "^2.13.0",
106 "concurrently": "^4.0.1",
107 "config": "^3.0.0", 106 "config": "^3.0.0",
108 "cookie-parser": "^1.4.3", 107 "cookie-parser": "^1.4.3",
109 "cors": "^2.8.1", 108 "cors": "^2.8.1",
@@ -111,14 +110,14 @@
111 "deep-object-diff": "^1.1.0", 110 "deep-object-diff": "^1.1.0",
112 "express": "^4.12.4", 111 "express": "^4.12.4",
113 "express-oauth-server": "^2.0.0", 112 "express-oauth-server": "^2.0.0",
114 "express-rate-limit": "^3.1.0", 113 "express-rate-limit": "^4.0.4",
115 "express-validator": "^5.0.0", 114 "express-validator": "^5.0.0",
116 "flat": "^4.1.0", 115 "flat": "^4.1.0",
117 "fluent-ffmpeg": "^2.1.0", 116 "fluent-ffmpeg": "^2.1.0",
118 "fs-extra": "^7.0.0", 117 "fs-extra": "^8.0.1",
119 "helmet": "^3.12.1", 118 "helmet": "^3.12.1",
120 "http-signature": "^1.2.0", 119 "http-signature": "^1.2.0",
121 "ip-anonymize": "^0.0.6", 120 "ip-anonymize": "^0.1.0",
122 "ipaddr.js": "1.9.0", 121 "ipaddr.js": "1.9.0",
123 "is-cidr": "^3.0.0", 122 "is-cidr": "^3.0.0",
124 "iso-639-3": "^1.0.1", 123 "iso-639-3": "^1.0.1",
@@ -142,25 +141,24 @@
142 "reflect-metadata": "^0.1.12", 141 "reflect-metadata": "^0.1.12",
143 "request": "^2.81.0", 142 "request": "^2.81.0",
144 "scripty": "^1.5.0", 143 "scripty": "^1.5.0",
145 "sequelize": "5.7.4", 144 "sequelize": "5.8.7",
146 "sequelize-typescript": "1.0.0-beta.2", 145 "sequelize-typescript": "1.0.0-beta.2",
147 "sharp": "^0.22.0", 146 "sharp": "^0.22.0",
148 "sitemap": "^2.1.0", 147 "sitemap": "^2.1.0",
149 "socket.io": "^2.2.0", 148 "socket.io": "^2.2.0",
150 "srt-to-vtt": "^1.1.2", 149 "srt-to-vtt": "^1.1.2",
151 "summon-install": "^0.4.3",
152 "useragent": "^2.3.0", 150 "useragent": "^2.3.0",
153 "uuid": "^3.1.0", 151 "uuid": "^3.1.0",
154 "validator": "^10.2.0", 152 "validator": "^11.0.0",
155 "webfinger.js": "^2.6.6", 153 "webfinger.js": "^2.6.6",
156 "webtorrent": "^0.103.0", 154 "webtorrent": "^0.103.0",
157 "winston": "3.2.1", 155 "winston": "3.2.1",
158 "ws": "^6.0.0", 156 "ws": "^7.0.0",
159 "youtube-dl": "^1.12.2" 157 "youtube-dl": "^2.0.0"
160 }, 158 },
161 "devDependencies": { 159 "devDependencies": {
162 "@types/apicache": "^1.2.0", 160 "@types/apicache": "^1.2.0",
163 "@types/async": "^2.0.40", 161 "@types/async": "^3.0.0",
164 "@types/async-lock": "^1.1.0", 162 "@types/async-lock": "^1.1.0",
165 "@types/bcrypt": "^3.0.0", 163 "@types/bcrypt": "^3.0.0",
166 "@types/bluebird": "3.5.21", 164 "@types/bluebird": "3.5.21",
@@ -174,7 +172,7 @@
174 "@types/express": "^4.0.35", 172 "@types/express": "^4.0.35",
175 "@types/express-rate-limit": "^3.3.0", 173 "@types/express-rate-limit": "^3.3.0",
176 "@types/fluent-ffmpeg": "^2.1.8", 174 "@types/fluent-ffmpeg": "^2.1.8",
177 "@types/fs-extra": "^5.0.4", 175 "@types/fs-extra": "^7.0.0",
178 "@types/libxmljs": "^0.18.0", 176 "@types/libxmljs": "^0.18.0",
179 "@types/lodash": "^4.14.64", 177 "@types/lodash": "^4.14.64",
180 "@types/magnet-uri": "^5.1.1", 178 "@types/magnet-uri": "^5.1.1",
@@ -185,7 +183,7 @@
185 "@types/morgan": "^1.7.32", 183 "@types/morgan": "^1.7.32",
186 "@types/multer": "^1.3.3", 184 "@types/multer": "^1.3.3",
187 "@types/node": "^10.0.8", 185 "@types/node": "^10.0.8",
188 "@types/nodemailer": "^4.3.1", 186 "@types/nodemailer": "^6.2.0",
189 "@types/oauth2-server": "^3.0.8", 187 "@types/oauth2-server": "^3.0.8",
190 "@types/pem": "^1.9.3", 188 "@types/pem": "^1.9.3",
191 "@types/redis": "^2.8.5", 189 "@types/redis": "^2.8.5",
@@ -199,18 +197,20 @@
199 "chai": "^4.1.1", 197 "chai": "^4.1.1",
200 "chai-json-schema": "^1.5.0", 198 "chai-json-schema": "^1.5.0",
201 "chai-xml": "^0.3.2", 199 "chai-xml": "^0.3.2",
202 "husky": "^1.0.0-rc.4", 200 "concurrently": "^4.1.0",
201 "husky": "^2.4.0",
203 "libxmljs": "0.19.5", 202 "libxmljs": "0.19.5",
204 "lint-staged": "^8.0.4", 203 "lint-staged": "^8.0.4",
205 "maildev": "^1.0.0-rc3", 204 "maildev": "^1.0.0-rc3",
206 "marked-man": "^0.4.2", 205 "marked-man": "^0.6.0",
207 "mocha": "^6.0.0", 206 "mocha": "^6.0.0",
207 "mocha-parallel-tests": "^2.1.0",
208 "nodemon": "^1.18.6", 208 "nodemon": "^1.18.6",
209 "sass-lint": "^1.12.1", 209 "sass-lint": "^1.12.1",
210 "source-map-support": "^0.5.0", 210 "source-map-support": "^0.5.0",
211 "supertest": "^4.0.2", 211 "supertest": "^4.0.2",
212 "swagger-cli": "^2.2.0", 212 "swagger-cli": "^2.2.0",
213 "ts-node": "8.0.3", 213 "ts-node": "8.2.0",
214 "tslint": "^5.7.0", 214 "tslint": "^5.7.0",
215 "tslint-config-standard": "^8.0.1", 215 "tslint-config-standard": "^8.0.1",
216 "typescript": "^3.4.3", 216 "typescript": "^3.4.3",
@@ -219,8 +219,5 @@
219 "scripty": { 219 "scripty": {
220 "silent": true 220 "silent": true
221 }, 221 },
222 "summon": {
223 "silent": true
224 },
225 "sasslintConfig": "client/.sass-lint.yml" 222 "sasslintConfig": "client/.sass-lint.yml"
226} 223}
diff --git a/scripts/clean/server/test.sh b/scripts/clean/server/test.sh
index 5694ac922..34afd6a9d 100755
--- a/scripts/clean/server/test.sh
+++ b/scripts/clean/server/test.sh
@@ -17,8 +17,11 @@ removeFiles () {
17} 17}
18 18
19dropRedis () { 19dropRedis () {
20 redis-cli KEYS "bull-localhost:900$1*" | grep -v empty | xargs --no-run-if-empty redis-cli DEL 20 port=$((9000+$1))
21 redis-cli KEYS "redis-localhost:900$1*" | grep -v empty | xargs --no-run-if-empty redis-cli DEL 21
22 redis-cli KEYS "bull-localhost:$port*" | grep -v empty | xargs --no-run-if-empty redis-cli DEL
23 redis-cli KEYS "redis-localhost:$port*" | grep -v empty | xargs --no-run-if-empty redis-cli DEL
24 redis-cli KEYS "*redis-localhost:$port-" | grep -v empty | xargs --no-run-if-empty redis-cli DEL
22} 25}
23 26
24seq=$(seq 1 6) 27seq=$(seq 1 6)
diff --git a/scripts/create-transcoding-job.ts b/scripts/create-transcoding-job.ts
index 4a677eacb..2b7cb5177 100755
--- a/scripts/create-transcoding-job.ts
+++ b/scripts/create-transcoding-job.ts
@@ -2,6 +2,7 @@ import * as program from 'commander'
2import { VideoModel } from '../server/models/video/video' 2import { VideoModel } from '../server/models/video/video'
3import { initDatabaseModels } from '../server/initializers' 3import { initDatabaseModels } from '../server/initializers'
4import { JobQueue } from '../server/lib/job-queue' 4import { JobQueue } from '../server/lib/job-queue'
5import { VideoTranscodingPayload } from '../server/lib/job-queue/handlers/video-transcoding'
5 6
6program 7program
7 .option('-v, --video [videoUUID]', 'Video UUID') 8 .option('-v, --video [videoUUID]', 'Video UUID')
@@ -31,15 +32,9 @@ async function run () {
31 const video = await VideoModel.loadByUUIDWithFile(program['video']) 32 const video = await VideoModel.loadByUUIDWithFile(program['video'])
32 if (!video) throw new Error('Video not found.') 33 if (!video) throw new Error('Video not found.')
33 34
34 const dataInput = { 35 const dataInput: VideoTranscodingPayload = program.resolution !== undefined
35 videoUUID: video.uuid, 36 ? { type: 'new-resolution' as 'new-resolution', videoUUID: video.uuid, isNewVideo: false, resolution: program.resolution }
36 isNewVideo: false, 37 : { type: 'optimize' as 'optimize', videoUUID: video.uuid, isNewVideo: false }
37 resolution: undefined
38 }
39
40 if (program.resolution !== undefined) {
41 dataInput.resolution = program.resolution
42 }
43 38
44 await JobQueue.Instance.init() 39 await JobQueue.Instance.init()
45 await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) 40 await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput })
diff --git a/scripts/setup/cli.sh b/scripts/setup/cli.sh
new file mode 100755
index 000000000..9808868d3
--- /dev/null
+++ b/scripts/setup/cli.sh
@@ -0,0 +1,16 @@
1#!/bin/sh
2
3set -eu
4
5NOCLIENT=1 yarn install --pure-lockfile
6
7rm -rf ./dist/server/tools/
8
9(
10 cd ./server/tools
11 yarn install --pure-lockfile
12)
13
14npm run tsc -- --build ./server/tools/tsconfig.json
15
16mv "./server/tools/node_modules" "./dist/server/tools"
diff --git a/scripts/test.sh b/scripts/test.sh
index cf8895365..5ec7a5920 100755
--- a/scripts/test.sh
+++ b/scripts/test.sh
@@ -3,6 +3,8 @@
3set -eu 3set -eu
4 4
5npm run build:server 5npm run build:server
6npm run setup:cli
7
6npm run travis -- lint 8npm run travis -- lint
7 9
8mocha --exit --require ts-node/register/type-check --bail server/tests/index.ts 10mocha --exit --require ts-node/register/type-check --bail server/tests/index.ts
diff --git a/scripts/travis.sh b/scripts/travis.sh
index 3557816c8..664d9fd6c 100755
--- a/scripts/travis.sh
+++ b/scripts/travis.sh
@@ -17,19 +17,20 @@ if [ "$1" = "misc" ]; then
17 server/tests/helpers/index.ts 17 server/tests/helpers/index.ts
18elif [ "$1" = "cli" ]; then 18elif [ "$1" = "cli" ]; then
19 npm run build:server 19 npm run build:server
20 CC=gcc-4.9 CXX=g++-4.9 npm run setup:cli
20 mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/cli/index.ts 21 mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/cli/index.ts
21elif [ "$1" = "api-1" ]; then 22elif [ "$1" = "api-1" ]; then
22 npm run build:server 23 npm run build:server
23 mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/api/index-1.ts 24 sh ./server/tests/api/travis-1.sh 2
24elif [ "$1" = "api-2" ]; then 25elif [ "$1" = "api-2" ]; then
25 npm run build:server 26 npm run build:server
26 mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/api/index-2.ts 27 sh ./server/tests/api/travis-2.sh 2
27elif [ "$1" = "api-3" ]; then 28elif [ "$1" = "api-3" ]; then
28 npm run build:server 29 npm run build:server
29 mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/api/index-3.ts 30 sh ./server/tests/api/travis-3.sh 2
30elif [ "$1" = "api-4" ]; then 31elif [ "$1" = "api-4" ]; then
31 npm run build:server 32 npm run build:server
32 mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/api/index-4.ts 33 sh ./server/tests/api/travis-4.sh 2
33elif [ "$1" = "lint" ]; then 34elif [ "$1" = "lint" ]; then
34 npm run tslint -- --project ./tsconfig.json -c ./tslint.json server.ts "server/**/*.ts" "shared/**/*.ts" 35 npm run tslint -- --project ./tsconfig.json -c ./tslint.json server.ts "server/**/*.ts" "shared/**/*.ts"
35 36
diff --git a/server/assets/default-audio-background.jpg b/server/assets/default-audio-background.jpg
new file mode 100644
index 000000000..a19173eac
--- /dev/null
+++ b/server/assets/default-audio-background.jpg
Binary files differ
diff --git a/server/controllers/api/accounts.ts b/server/controllers/api/accounts.ts
index 8d4db1e75..5a1d652f2 100644
--- a/server/controllers/api/accounts.ts
+++ b/server/controllers/api/accounts.ts
@@ -16,7 +16,8 @@ import {
16 accountNameWithHostGetValidator, 16 accountNameWithHostGetValidator,
17 accountsSortValidator, 17 accountsSortValidator,
18 ensureAuthUserOwnsAccountValidator, 18 ensureAuthUserOwnsAccountValidator,
19 videosSortValidator 19 videosSortValidator,
20 videoChannelsSortValidator
20} from '../../middlewares/validators' 21} from '../../middlewares/validators'
21import { AccountModel } from '../../models/account/account' 22import { AccountModel } from '../../models/account/account'
22import { AccountVideoRateModel } from '../../models/account/account-video-rate' 23import { AccountVideoRateModel } from '../../models/account/account-video-rate'
@@ -56,6 +57,10 @@ accountsRouter.get('/:accountName/videos',
56 57
57accountsRouter.get('/:accountName/video-channels', 58accountsRouter.get('/:accountName/video-channels',
58 asyncMiddleware(accountNameWithHostGetValidator), 59 asyncMiddleware(accountNameWithHostGetValidator),
60 paginationValidator,
61 videoChannelsSortValidator,
62 setDefaultSort,
63 setDefaultPagination,
59 asyncMiddleware(listAccountChannels) 64 asyncMiddleware(listAccountChannels)
60) 65)
61 66
@@ -108,7 +113,14 @@ async function listAccounts (req: express.Request, res: express.Response) {
108} 113}
109 114
110async function listAccountChannels (req: express.Request, res: express.Response) { 115async function listAccountChannels (req: express.Request, res: express.Response) {
111 const resultList = await VideoChannelModel.listByAccount(res.locals.account.id) 116 const options = {
117 accountId: res.locals.account.id,
118 start: req.query.start,
119 count: req.query.count,
120 sort: req.query.sort
121 }
122
123 const resultList = await VideoChannelModel.listByAccount(options)
112 124
113 return res.json(getFormattedObjects(resultList.data, resultList.total)) 125 return res.json(getFormattedObjects(resultList.data, resultList.total))
114} 126}
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index 40012c03b..27c416a12 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -51,7 +51,7 @@ async function getConfig (req: express.Request, res: express.Response) {
51 if (serverCommit === undefined) serverCommit = await getServerCommit() 51 if (serverCommit === undefined) serverCommit = await getServerCommit()
52 52
53 const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) 53 const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
54 .filter(key => CONFIG.TRANSCODING.ENABLED === CONFIG.TRANSCODING.RESOLUTIONS[key] === true) 54 .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
55 .map(r => parseInt(r, 10)) 55 .map(r => parseInt(r, 10))
56 56
57 const json: ServerConfig = { 57 const json: ServerConfig = {
@@ -255,6 +255,7 @@ function customConfig (): CustomConfig {
255 transcoding: { 255 transcoding: {
256 enabled: CONFIG.TRANSCODING.ENABLED, 256 enabled: CONFIG.TRANSCODING.ENABLED,
257 allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS, 257 allowAdditionalExtensions: CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS,
258 allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES,
258 threads: CONFIG.TRANSCODING.THREADS, 259 threads: CONFIG.TRANSCODING.THREADS,
259 resolutions: { 260 resolutions: {
260 '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ], 261 '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ],
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts
index 0aafba66e..48a6c63b8 100644
--- a/server/controllers/api/users/index.ts
+++ b/server/controllers/api/users/index.ts
@@ -46,14 +46,18 @@ import { mySubscriptionsRouter } from './my-subscriptions'
46import { CONFIG } from '../../../initializers/config' 46import { CONFIG } from '../../../initializers/config'
47import { sequelizeTypescript } from '../../../initializers/database' 47import { sequelizeTypescript } from '../../../initializers/database'
48import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' 48import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
49import { UserRegister } from '../../../../shared/models/users/user-register.model'
49 50
50const auditLogger = auditLoggerFactory('users') 51const auditLogger = auditLoggerFactory('users')
51 52
52const loginRateLimiter = new RateLimit({ 53// FIXME: https://github.com/nfriedly/express-rate-limit/issues/138
54// @ts-ignore
55const loginRateLimiter = RateLimit({
53 windowMs: RATES_LIMIT.LOGIN.WINDOW_MS, 56 windowMs: RATES_LIMIT.LOGIN.WINDOW_MS,
54 max: RATES_LIMIT.LOGIN.MAX 57 max: RATES_LIMIT.LOGIN.MAX
55}) 58})
56 59
60// @ts-ignore
57const askSendEmailLimiter = new RateLimit({ 61const askSendEmailLimiter = new RateLimit({
58 windowMs: RATES_LIMIT.ASK_SEND_EMAIL.WINDOW_MS, 62 windowMs: RATES_LIMIT.ASK_SEND_EMAIL.WINDOW_MS,
59 max: RATES_LIMIT.ASK_SEND_EMAIL.MAX 63 max: RATES_LIMIT.ASK_SEND_EMAIL.MAX
@@ -189,15 +193,14 @@ async function createUser (req: express.Request, res: express.Response) {
189 user: { 193 user: {
190 id: user.id, 194 id: user.id,
191 account: { 195 account: {
192 id: account.id, 196 id: account.id
193 uuid: account.Actor.uuid
194 } 197 }
195 } 198 }
196 }).end() 199 }).end()
197} 200}
198 201
199async function registerUser (req: express.Request, res: express.Response) { 202async function registerUser (req: express.Request, res: express.Response) {
200 const body: UserCreate = req.body 203 const body: UserRegister = req.body
201 204
202 const userToCreate = new UserModel({ 205 const userToCreate = new UserModel({
203 username: body.username, 206 username: body.username,
@@ -211,7 +214,7 @@ async function registerUser (req: express.Request, res: express.Response) {
211 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null 214 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
212 }) 215 })
213 216
214 const { user } = await createUserAccountAndChannelAndPlaylist(userToCreate) 217 const { user } = await createUserAccountAndChannelAndPlaylist(userToCreate, body.channel)
215 218
216 auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON())) 219 auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON()))
217 logger.info('User %s with its channel and account registered.', body.username) 220 logger.info('User %s with its channel and account registered.', body.username)
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts
index 3d6dbfe70..81a03a62b 100644
--- a/server/controllers/api/video-channel.ts
+++ b/server/controllers/api/video-channel.ts
@@ -19,7 +19,7 @@ import { VideoChannelModel } from '../../models/video/video-channel'
19import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators' 19import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators'
20import { sendUpdateActor } from '../../lib/activitypub/send' 20import { sendUpdateActor } from '../../lib/activitypub/send'
21import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' 21import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared'
22import { createVideoChannel } from '../../lib/video-channel' 22import { createVideoChannel, federateAllVideosOfChannel } from '../../lib/video-channel'
23import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' 23import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
24import { setAsyncActorKeys } from '../../lib/activitypub' 24import { setAsyncActorKeys } from '../../lib/activitypub'
25import { AccountModel } from '../../models/account/account' 25import { AccountModel } from '../../models/account/account'
@@ -143,15 +143,14 @@ async function addVideoChannel (req: express.Request, res: express.Response) {
143 }) 143 })
144 144
145 setAsyncActorKeys(videoChannelCreated.Actor) 145 setAsyncActorKeys(videoChannelCreated.Actor)
146 .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.uuid, { err })) 146 .catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.url, { err }))
147 147
148 auditLogger.create(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelCreated.toFormattedJSON())) 148 auditLogger.create(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelCreated.toFormattedJSON()))
149 logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid) 149 logger.info('Video channel %s created.', videoChannelCreated.Actor.url)
150 150
151 return res.json({ 151 return res.json({
152 videoChannel: { 152 videoChannel: {
153 id: videoChannelCreated.id, 153 id: videoChannelCreated.id
154 uuid: videoChannelCreated.Actor.uuid
155 } 154 }
156 }).end() 155 }).end()
157} 156}
@@ -161,6 +160,7 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
161 const videoChannelFieldsSave = videoChannelInstance.toJSON() 160 const videoChannelFieldsSave = videoChannelInstance.toJSON()
162 const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()) 161 const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON())
163 const videoChannelInfoToUpdate = req.body as VideoChannelUpdate 162 const videoChannelInfoToUpdate = req.body as VideoChannelUpdate
163 let doBulkVideoUpdate = false
164 164
165 try { 165 try {
166 await sequelizeTypescript.transaction(async t => { 166 await sequelizeTypescript.transaction(async t => {
@@ -168,9 +168,18 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
168 transaction: t 168 transaction: t
169 } 169 }
170 170
171 if (videoChannelInfoToUpdate.displayName !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.displayName) 171 if (videoChannelInfoToUpdate.displayName !== undefined) videoChannelInstance.name = videoChannelInfoToUpdate.displayName
172 if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description) 172 if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.description = videoChannelInfoToUpdate.description
173 if (videoChannelInfoToUpdate.support !== undefined) videoChannelInstance.set('support', videoChannelInfoToUpdate.support) 173
174 if (videoChannelInfoToUpdate.support !== undefined) {
175 const oldSupportField = videoChannelInstance.support
176 videoChannelInstance.support = videoChannelInfoToUpdate.support
177
178 if (videoChannelInfoToUpdate.bulkVideosSupportUpdate === true && oldSupportField !== videoChannelInfoToUpdate.support) {
179 doBulkVideoUpdate = true
180 await VideoModel.bulkUpdateSupportField(videoChannelInstance, t)
181 }
182 }
174 183
175 const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions) 184 const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions)
176 await sendUpdateActor(videoChannelInstanceUpdated, t) 185 await sendUpdateActor(videoChannelInstanceUpdated, t)
@@ -180,7 +189,8 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
180 new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()), 189 new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()),
181 oldVideoChannelAuditKeys 190 oldVideoChannelAuditKeys
182 ) 191 )
183 logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.Actor.uuid) 192
193 logger.info('Video channel %s updated.', videoChannelInstance.Actor.url)
184 }) 194 })
185 } catch (err) { 195 } catch (err) {
186 logger.debug('Cannot update the video channel.', { err }) 196 logger.debug('Cannot update the video channel.', { err })
@@ -193,7 +203,12 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
193 throw err 203 throw err
194 } 204 }
195 205
196 return res.type('json').status(204).end() 206 res.type('json').status(204).end()
207
208 // Don't process in a transaction, and after the response because it could be long
209 if (doBulkVideoUpdate) {
210 await federateAllVideosOfChannel(videoChannelInstance)
211 }
197} 212}
198 213
199async function removeVideoChannel (req: express.Request, res: express.Response) { 214async function removeVideoChannel (req: express.Request, res: express.Response) {
@@ -205,7 +220,7 @@ async function removeVideoChannel (req: express.Request, res: express.Response)
205 await videoChannelInstance.destroy({ transaction: t }) 220 await videoChannelInstance.destroy({ transaction: t })
206 221
207 auditLogger.delete(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelInstance.toFormattedJSON())) 222 auditLogger.delete(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()))
208 logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid) 223 logger.info('Video channel %s deleted.', videoChannelInstance.Actor.url)
209 }) 224 })
210 225
211 return res.type('json').status(204).end() 226 return res.type('json').status(204).end()
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts
index a17136401..62490e63b 100644
--- a/server/controllers/api/video-playlist.ts
+++ b/server/controllers/api/video-playlist.ts
@@ -203,7 +203,9 @@ async function updateVideoPlaylist (req: express.Request, res: express.Response)
203 const videoPlaylistInstance = res.locals.videoPlaylist 203 const videoPlaylistInstance = res.locals.videoPlaylist
204 const videoPlaylistFieldsSave = videoPlaylistInstance.toJSON() 204 const videoPlaylistFieldsSave = videoPlaylistInstance.toJSON()
205 const videoPlaylistInfoToUpdate = req.body as VideoPlaylistUpdate 205 const videoPlaylistInfoToUpdate = req.body as VideoPlaylistUpdate
206
206 const wasPrivatePlaylist = videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE 207 const wasPrivatePlaylist = videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE
208 const wasNotPrivatePlaylist = videoPlaylistInstance.privacy !== VideoPlaylistPrivacy.PRIVATE
207 209
208 const thumbnailField = req.files['thumbnailfile'] 210 const thumbnailField = req.files['thumbnailfile']
209 const thumbnailModel = thumbnailField 211 const thumbnailModel = thumbnailField
@@ -232,6 +234,10 @@ async function updateVideoPlaylist (req: express.Request, res: express.Response)
232 234
233 if (videoPlaylistInfoToUpdate.privacy !== undefined) { 235 if (videoPlaylistInfoToUpdate.privacy !== undefined) {
234 videoPlaylistInstance.privacy = parseInt(videoPlaylistInfoToUpdate.privacy.toString(), 10) 236 videoPlaylistInstance.privacy = parseInt(videoPlaylistInfoToUpdate.privacy.toString(), 10)
237
238 if (wasNotPrivatePlaylist === true && videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE) {
239 await sendDeleteVideoPlaylist(videoPlaylistInstance, t)
240 }
235 } 241 }
236 242
237 const playlistUpdated = await videoPlaylistInstance.save(sequelizeOptions) 243 const playlistUpdated = await videoPlaylistInstance.save(sequelizeOptions)
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index 1a18a8ae8..5ebd8fbc4 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -6,7 +6,14 @@ import { logger } from '../../../helpers/logger'
6import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' 6import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger'
7import { getFormattedObjects, getServerActor } from '../../../helpers/utils' 7import { getFormattedObjects, getServerActor } from '../../../helpers/utils'
8import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist' 8import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist'
9import { MIMETYPES, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../initializers/constants' 9import {
10 DEFAULT_AUDIO_RESOLUTION,
11 MIMETYPES,
12 VIDEO_CATEGORIES,
13 VIDEO_LANGUAGES,
14 VIDEO_LICENCES,
15 VIDEO_PRIVACIES
16} from '../../../initializers/constants'
10import { 17import {
11 changeVideoChannelShare, 18 changeVideoChannelShare,
12 federateVideoIfNeeded, 19 federateVideoIfNeeded,
@@ -54,6 +61,7 @@ import { CONFIG } from '../../../initializers/config'
54import { sequelizeTypescript } from '../../../initializers/database' 61import { sequelizeTypescript } from '../../../initializers/database'
55import { createVideoMiniatureFromExisting, generateVideoMiniature } from '../../../lib/thumbnail' 62import { createVideoMiniatureFromExisting, generateVideoMiniature } from '../../../lib/thumbnail'
56import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' 63import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type'
64import { VideoTranscodingPayload } from '../../../lib/job-queue/handlers/video-transcoding'
57 65
58const auditLogger = auditLoggerFactory('videos') 66const auditLogger = auditLoggerFactory('videos')
59const videosRouter = express.Router() 67const videosRouter = express.Router()
@@ -191,17 +199,17 @@ async function addVideo (req: express.Request, res: express.Response) {
191 const video = new VideoModel(videoData) 199 const video = new VideoModel(videoData)
192 video.url = getVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object 200 video.url = getVideoActivityPubUrl(video) // We use the UUID, so set the URL after building the object
193 201
194 // Build the file object 202 const videoFile = new VideoFileModel({
195 const { videoFileResolution } = await getVideoFileResolution(videoPhysicalFile.path)
196 const fps = await getVideoFileFPS(videoPhysicalFile.path)
197
198 const videoFileData = {
199 extname: extname(videoPhysicalFile.filename), 203 extname: extname(videoPhysicalFile.filename),
200 resolution: videoFileResolution, 204 size: videoPhysicalFile.size
201 size: videoPhysicalFile.size, 205 })
202 fps 206
207 if (videoFile.isAudio()) {
208 videoFile.resolution = DEFAULT_AUDIO_RESOLUTION
209 } else {
210 videoFile.fps = await getVideoFileFPS(videoPhysicalFile.path)
211 videoFile.resolution = (await getVideoFileResolution(videoPhysicalFile.path)).videoFileResolution
203 } 212 }
204 const videoFile = new VideoFileModel(videoFileData)
205 213
206 // Move physical file 214 // Move physical file
207 const videoDir = CONFIG.STORAGE.VIDEOS_DIR 215 const videoDir = CONFIG.STORAGE.VIDEOS_DIR
@@ -279,9 +287,21 @@ async function addVideo (req: express.Request, res: express.Response) {
279 287
280 if (video.state === VideoState.TO_TRANSCODE) { 288 if (video.state === VideoState.TO_TRANSCODE) {
281 // Put uuid because we don't have id auto incremented for now 289 // Put uuid because we don't have id auto incremented for now
282 const dataInput = { 290 let dataInput: VideoTranscodingPayload
283 videoUUID: videoCreated.uuid, 291
284 isNewVideo: true 292 if (videoFile.isAudio()) {
293 dataInput = {
294 type: 'merge-audio' as 'merge-audio',
295 resolution: DEFAULT_AUDIO_RESOLUTION,
296 videoUUID: videoCreated.uuid,
297 isNewVideo: true
298 }
299 } else {
300 dataInput = {
301 type: 'optimize' as 'optimize',
302 videoUUID: videoCreated.uuid,
303 isNewVideo: true
304 }
285 } 305 }
286 306
287 await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) 307 await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput })
@@ -300,7 +320,9 @@ async function updateVideo (req: express.Request, res: express.Response) {
300 const videoFieldsSave = videoInstance.toJSON() 320 const videoFieldsSave = videoInstance.toJSON()
301 const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON()) 321 const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON())
302 const videoInfoToUpdate: VideoUpdate = req.body 322 const videoInfoToUpdate: VideoUpdate = req.body
323
303 const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE 324 const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE
325 const wasNotPrivateVideo = videoInstance.privacy !== VideoPrivacy.PRIVATE
304 const wasUnlistedVideo = videoInstance.privacy === VideoPrivacy.UNLISTED 326 const wasUnlistedVideo = videoInstance.privacy === VideoPrivacy.UNLISTED
305 327
306 // Process thumbnail or create it from the video 328 // Process thumbnail or create it from the video
@@ -336,9 +358,15 @@ async function updateVideo (req: express.Request, res: express.Response) {
336 const newPrivacy = parseInt(videoInfoToUpdate.privacy.toString(), 10) 358 const newPrivacy = parseInt(videoInfoToUpdate.privacy.toString(), 10)
337 videoInstance.privacy = newPrivacy 359 videoInstance.privacy = newPrivacy
338 360
361 // The video was private, and is not anymore -> publish it
339 if (wasPrivateVideo === true && newPrivacy !== VideoPrivacy.PRIVATE) { 362 if (wasPrivateVideo === true && newPrivacy !== VideoPrivacy.PRIVATE) {
340 videoInstance.publishedAt = new Date() 363 videoInstance.publishedAt = new Date()
341 } 364 }
365
366 // The video was not private, but now it is -> we need to unfederate it
367 if (wasNotPrivateVideo === true && newPrivacy === VideoPrivacy.PRIVATE) {
368 await VideoModel.sendDelete(videoInstance, { transaction: t })
369 }
342 } 370 }
343 371
344 const videoInstanceUpdated = await videoInstance.save(sequelizeOptions) 372 const videoInstanceUpdated = await videoInstance.save(sequelizeOptions)
diff --git a/server/controllers/static.ts b/server/controllers/static.ts
index fb2e7742a..a6b462443 100644
--- a/server/controllers/static.ts
+++ b/server/controllers/static.ts
@@ -194,7 +194,7 @@ async function getVideoCaption (req: express.Request, res: express.Response) {
194 return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE }) 194 return res.sendFile(result.path, { maxAge: STATIC_MAX_AGE })
195} 195}
196 196
197async function generateNodeinfo (req: express.Request, res: express.Response, next: express.NextFunction) { 197async function generateNodeinfo (req: express.Request, res: express.Response) {
198 const { totalVideos } = await VideoModel.getStats() 198 const { totalVideos } = await VideoModel.getStats()
199 const { totalLocalVideoComments } = await VideoCommentModel.getStats() 199 const { totalLocalVideoComments } = await VideoCommentModel.getStats()
200 const { totalUsers } = await UserModel.getStats() 200 const { totalUsers } = await UserModel.getStats()
diff --git a/server/helpers/custom-validators/accounts.ts b/server/helpers/custom-validators/accounts.ts
index 146c7708e..31a2de5ca 100644
--- a/server/helpers/custom-validators/accounts.ts
+++ b/server/helpers/custom-validators/accounts.ts
@@ -1,7 +1,6 @@
1import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
2import { Response } from 'express' 2import { Response } from 'express'
3import 'express-validator' 3import 'express-validator'
4import * as validator from 'validator'
5import { AccountModel } from '../../models/account/account' 4import { AccountModel } from '../../models/account/account'
6import { isUserDescriptionValid, isUserUsernameValid } from './users' 5import { isUserDescriptionValid, isUserUsernameValid } from './users'
7import { exists } from './misc' 6import { exists } from './misc'
@@ -18,14 +17,8 @@ function isAccountDescriptionValid (value: string) {
18 return isUserDescriptionValid(value) 17 return isUserDescriptionValid(value)
19} 18}
20 19
21function doesAccountIdExist (id: number | string, res: Response, sendNotFound = true) { 20function doesAccountIdExist (id: number, res: Response, sendNotFound = true) {
22 let promise: Bluebird<AccountModel> 21 const promise = AccountModel.load(id)
23
24 if (validator.isInt('' + id)) {
25 promise = AccountModel.load(+id)
26 } else { // UUID
27 promise = AccountModel.loadByUUID('' + id)
28 }
29 22
30 return doesAccountExist(promise, res, sendNotFound) 23 return doesAccountExist(promise, res, sendNotFound)
31} 24}
diff --git a/server/helpers/custom-validators/activitypub/video-comments.ts b/server/helpers/custom-validators/activitypub/video-comments.ts
index 26c8c4cc6..e04c5388f 100644
--- a/server/helpers/custom-validators/activitypub/video-comments.ts
+++ b/server/helpers/custom-validators/activitypub/video-comments.ts
@@ -36,7 +36,8 @@ function normalizeComment (comment: any) {
36 if (!comment) return 36 if (!comment) return
37 37
38 if (typeof comment.url !== 'string') { 38 if (typeof comment.url !== 'string') {
39 comment.url = comment.url.href || comment.url.url 39 if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url
40 else comment.url = comment.id
40 } 41 }
41 42
42 return 43 return
diff --git a/server/helpers/custom-validators/video-channels.ts b/server/helpers/custom-validators/video-channels.ts
index fd56b9a70..f818ce8f1 100644
--- a/server/helpers/custom-validators/video-channels.ts
+++ b/server/helpers/custom-validators/video-channels.ts
@@ -26,13 +26,8 @@ async function doesLocalVideoChannelNameExist (name: string, res: express.Respon
26 return processVideoChannelExist(videoChannel, res) 26 return processVideoChannelExist(videoChannel, res)
27} 27}
28 28
29async function doesVideoChannelIdExist (id: number | string, res: express.Response) { 29async function doesVideoChannelIdExist (id: number, res: express.Response) {
30 let videoChannel: VideoChannelModel 30 const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id)
31 if (validator.isInt('' + id)) {
32 videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id)
33 } else { // UUID
34 videoChannel = await VideoChannelModel.loadByUUIDAndPopulateAccount('' + id)
35 }
36 31
37 return processVideoChannelExist(videoChannel, res) 32 return processVideoChannelExist(videoChannel, res)
38} 33}
diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts
index e0a1d56a5..00f3f198b 100644
--- a/server/helpers/express-utils.ts
+++ b/server/helpers/express-utils.ts
@@ -74,7 +74,18 @@ function createReqFiles (
74 }, 74 },
75 75
76 filename: async (req, file, cb) => { 76 filename: async (req, file, cb) => {
77 const extension = mimeTypes[ file.mimetype ] || extname(file.originalname) 77 let extension: string
78 const fileExtension = extname(file.originalname)
79 const extensionFromMimetype = mimeTypes[ file.mimetype ]
80
81 // Take the file extension if we don't understand the mime type
82 // We have the OGG/OGV exception too because firefox sends a bad mime type when sending an OGG file
83 if (fileExtension === '.ogg' || fileExtension === '.ogv' || !extensionFromMimetype) {
84 extension = fileExtension
85 } else {
86 extension = extensionFromMimetype
87 }
88
78 let randomString = '' 89 let randomString = ''
79 90
80 try { 91 try {
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts
index 76b744de8..8041e7b3b 100644
--- a/server/helpers/ffmpeg-utils.ts
+++ b/server/helpers/ffmpeg-utils.ts
@@ -1,6 +1,6 @@
1import * as ffmpeg from 'fluent-ffmpeg' 1import * as ffmpeg from 'fluent-ffmpeg'
2import { dirname, join } from 'path' 2import { dirname, join } from 'path'
3import { getTargetBitrate, VideoResolution } from '../../shared/models/videos' 3import { getTargetBitrate, getMaxBitrate, VideoResolution } from '../../shared/models/videos'
4import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants' 4import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants'
5import { processImage } from './image-utils' 5import { processImage } from './image-utils'
6import { logger } from './logger' 6import { logger } from './logger'
@@ -18,7 +18,8 @@ function computeResolutionsToTranscode (videoFileHeight: number) {
18 VideoResolution.H_360P, 18 VideoResolution.H_360P,
19 VideoResolution.H_720P, 19 VideoResolution.H_720P,
20 VideoResolution.H_240P, 20 VideoResolution.H_240P,
21 VideoResolution.H_1080P 21 VideoResolution.H_1080P,
22 VideoResolution.H_4K
22 ] 23 ]
23 24
24 for (const resolution of resolutions) { 25 for (const resolution of resolutions) {
@@ -31,7 +32,7 @@ function computeResolutionsToTranscode (videoFileHeight: number) {
31} 32}
32 33
33async function getVideoFileSize (path: string) { 34async function getVideoFileSize (path: string) {
34 const videoStream = await getVideoFileStream(path) 35 const videoStream = await getVideoStreamFromFile(path)
35 36
36 return { 37 return {
37 width: videoStream.width, 38 width: videoStream.width,
@@ -49,7 +50,7 @@ async function getVideoFileResolution (path: string) {
49} 50}
50 51
51async function getVideoFileFPS (path: string) { 52async function getVideoFileFPS (path: string) {
52 const videoStream = await getVideoFileStream(path) 53 const videoStream = await getVideoStreamFromFile(path)
53 54
54 for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { 55 for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) {
55 const valuesText: string = videoStream[key] 56 const valuesText: string = videoStream[key]
@@ -117,25 +118,50 @@ async function generateImageFromVideoFile (fromPath: string, folder: string, ima
117 } 118 }
118} 119}
119 120
120type TranscodeOptions = { 121type TranscodeOptionsType = 'hls' | 'quick-transcode' | 'video' | 'merge-audio'
122
123interface BaseTranscodeOptions {
124 type: TranscodeOptionsType
121 inputPath: string 125 inputPath: string
122 outputPath: string 126 outputPath: string
123 resolution: VideoResolution 127 resolution: VideoResolution
124 isPortraitMode?: boolean 128 isPortraitMode?: boolean
129}
125 130
126 hlsPlaylist?: { 131interface HLSTranscodeOptions extends BaseTranscodeOptions {
132 type: 'hls'
133 hlsPlaylist: {
127 videoFilename: string 134 videoFilename: string
128 } 135 }
129} 136}
130 137
138interface QuickTranscodeOptions extends BaseTranscodeOptions {
139 type: 'quick-transcode'
140}
141
142interface VideoTranscodeOptions extends BaseTranscodeOptions {
143 type: 'video'
144}
145
146interface MergeAudioTranscodeOptions extends BaseTranscodeOptions {
147 type: 'merge-audio'
148 audioPath: string
149}
150
151type TranscodeOptions = HLSTranscodeOptions | VideoTranscodeOptions | MergeAudioTranscodeOptions | QuickTranscodeOptions
152
131function transcode (options: TranscodeOptions) { 153function transcode (options: TranscodeOptions) {
132 return new Promise<void>(async (res, rej) => { 154 return new Promise<void>(async (res, rej) => {
133 try { 155 try {
134 let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING }) 156 let command = ffmpeg(options.inputPath, { niceness: FFMPEG_NICE.TRANSCODING })
135 .output(options.outputPath) 157 .output(options.outputPath)
136 158
137 if (options.hlsPlaylist) { 159 if (options.type === 'quick-transcode') {
160 command = await buildQuickTranscodeCommand(command)
161 } else if (options.type === 'hls') {
138 command = await buildHLSCommand(command, options) 162 command = await buildHLSCommand(command, options)
163 } else if (options.type === 'merge-audio') {
164 command = await buildAudioMergeCommand(command, options)
139 } else { 165 } else {
140 command = await buildx264Command(command, options) 166 command = await buildx264Command(command, options)
141 } 167 }
@@ -151,7 +177,7 @@ function transcode (options: TranscodeOptions) {
151 return rej(err) 177 return rej(err)
152 }) 178 })
153 .on('end', () => { 179 .on('end', () => {
154 return onTranscodingSuccess(options) 180 return fixHLSPlaylistIfNeeded(options)
155 .then(() => res()) 181 .then(() => res())
156 .catch(err => rej(err)) 182 .catch(err => rej(err))
157 }) 183 })
@@ -162,6 +188,30 @@ function transcode (options: TranscodeOptions) {
162 }) 188 })
163} 189}
164 190
191async function canDoQuickTranscode (path: string): Promise<boolean> {
192 // NOTE: This could be optimized by running ffprobe only once (but it runs fast anyway)
193 const videoStream = await getVideoStreamFromFile(path)
194 const parsedAudio = await audio.get(path)
195 const fps = await getVideoFileFPS(path)
196 const bitRate = await getVideoFileBitrate(path)
197 const resolution = await getVideoFileResolution(path)
198
199 // check video params
200 if (videoStream[ 'codec_name' ] !== 'h264') return false
201 if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false
202 if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false
203
204 // check audio params (if audio stream exists)
205 if (parsedAudio.audioStream) {
206 if (parsedAudio.audioStream[ 'codec_name' ] !== 'aac') return false
207
208 const maxAudioBitrate = audio.bitrate[ 'aac' ](parsedAudio.audioStream[ 'bit_rate' ])
209 if (maxAudioBitrate !== -1 && parsedAudio.audioStream[ 'bit_rate' ] > maxAudioBitrate) return false
210 }
211
212 return true
213}
214
165// --------------------------------------------------------------------------- 215// ---------------------------------------------------------------------------
166 216
167export { 217export {
@@ -169,16 +219,19 @@ export {
169 getVideoFileResolution, 219 getVideoFileResolution,
170 getDurationFromVideoFile, 220 getDurationFromVideoFile,
171 generateImageFromVideoFile, 221 generateImageFromVideoFile,
222 TranscodeOptions,
223 TranscodeOptionsType,
172 transcode, 224 transcode,
173 getVideoFileFPS, 225 getVideoFileFPS,
174 computeResolutionsToTranscode, 226 computeResolutionsToTranscode,
175 audio, 227 audio,
176 getVideoFileBitrate 228 getVideoFileBitrate,
229 canDoQuickTranscode
177} 230}
178 231
179// --------------------------------------------------------------------------- 232// ---------------------------------------------------------------------------
180 233
181async function buildx264Command (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { 234async function buildx264Command (command: ffmpeg.FfmpegCommand, options: VideoTranscodeOptions) {
182 let fps = await getVideoFileFPS(options.inputPath) 235 let fps = await getVideoFileFPS(options.inputPath)
183 // On small/medium resolutions, limit FPS 236 // On small/medium resolutions, limit FPS
184 if ( 237 if (
@@ -189,7 +242,7 @@ async function buildx264Command (command: ffmpeg.FfmpegCommand, options: Transco
189 fps = VIDEO_TRANSCODING_FPS.AVERAGE 242 fps = VIDEO_TRANSCODING_FPS.AVERAGE
190 } 243 }
191 244
192 command = await presetH264(command, options.resolution, fps) 245 command = await presetH264(command, options.inputPath, options.resolution, fps)
193 246
194 if (options.resolution !== undefined) { 247 if (options.resolution !== undefined) {
195 // '?x720' or '720x?' for example 248 // '?x720' or '720x?' for example
@@ -208,7 +261,29 @@ async function buildx264Command (command: ffmpeg.FfmpegCommand, options: Transco
208 return command 261 return command
209} 262}
210 263
211async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { 264async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: MergeAudioTranscodeOptions) {
265 command = command.loop(undefined)
266
267 command = await presetH264VeryFast(command, options.audioPath, options.resolution)
268
269 command = command.input(options.audioPath)
270 .videoFilter('scale=trunc(iw/2)*2:trunc(ih/2)*2') // Avoid "height not divisible by 2" error
271 .outputOption('-tune stillimage')
272 .outputOption('-shortest')
273
274 return command
275}
276
277async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) {
278 command = await presetCopy(command)
279
280 command = command.outputOption('-map_metadata -1') // strip all metadata
281 .outputOption('-movflags faststart')
282
283 return command
284}
285
286async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) {
212 const videoPath = getHLSVideoPath(options) 287 const videoPath = getHLSVideoPath(options)
213 288
214 command = await presetCopy(command) 289 command = await presetCopy(command)
@@ -224,26 +299,26 @@ async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: Transcod
224 return command 299 return command
225} 300}
226 301
227function getHLSVideoPath (options: TranscodeOptions) { 302function getHLSVideoPath (options: HLSTranscodeOptions) {
228 return `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}` 303 return `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}`
229} 304}
230 305
231async function onTranscodingSuccess (options: TranscodeOptions) { 306async function fixHLSPlaylistIfNeeded (options: TranscodeOptions) {
232 if (!options.hlsPlaylist) return 307 if (options.type !== 'hls') return
233 308
234 // Fix wrong mapping with some ffmpeg versions
235 const fileContent = await readFile(options.outputPath) 309 const fileContent = await readFile(options.outputPath)
236 310
237 const videoFileName = options.hlsPlaylist.videoFilename 311 const videoFileName = options.hlsPlaylist.videoFilename
238 const videoFilePath = getHLSVideoPath(options) 312 const videoFilePath = getHLSVideoPath(options)
239 313
314 // Fix wrong mapping with some ffmpeg versions
240 const newContent = fileContent.toString() 315 const newContent = fileContent.toString()
241 .replace(`#EXT-X-MAP:URI="${videoFilePath}",`, `#EXT-X-MAP:URI="${videoFileName}",`) 316 .replace(`#EXT-X-MAP:URI="${videoFilePath}",`, `#EXT-X-MAP:URI="${videoFileName}",`)
242 317
243 await writeFile(options.outputPath, newContent) 318 await writeFile(options.outputPath, newContent)
244} 319}
245 320
246function getVideoFileStream (path: string) { 321function getVideoStreamFromFile (path: string) {
247 return new Promise<any>((res, rej) => { 322 return new Promise<any>((res, rej) => {
248 ffmpeg.ffprobe(path, (err, metadata) => { 323 ffmpeg.ffprobe(path, (err, metadata) => {
249 if (err) return rej(err) 324 if (err) return rej(err)
@@ -263,44 +338,27 @@ function getVideoFileStream (path: string) {
263 * and quality. Superfast and ultrafast will give you better 338 * and quality. Superfast and ultrafast will give you better
264 * performance, but then quality is noticeably worse. 339 * performance, but then quality is noticeably worse.
265 */ 340 */
266async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, resolution: VideoResolution, fps: number): Promise<ffmpeg.FfmpegCommand> { 341async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, input: string, resolution: VideoResolution, fps?: number) {
267 let localCommand = await presetH264(command, resolution, fps) 342 let localCommand = await presetH264(command, input, resolution, fps)
343
268 localCommand = localCommand.outputOption('-preset:v veryfast') 344 localCommand = localCommand.outputOption('-preset:v veryfast')
269 .outputOption([ '--aq-mode=2', '--aq-strength=1.3' ]) 345
270 /* 346 /*
271 MAIN reference: https://slhck.info/video/2017/03/01/rate-control.html 347 MAIN reference: https://slhck.info/video/2017/03/01/rate-control.html
272 Our target situation is closer to a livestream than a stream, 348 Our target situation is closer to a livestream than a stream,
273 since we want to reduce as much a possible the encoding burden, 349 since we want to reduce as much a possible the encoding burden,
274 altough not to the point of a livestream where there is a hard 350 although not to the point of a livestream where there is a hard
275 constraint on the frames per second to be encoded. 351 constraint on the frames per second to be encoded.
276
277 why '--aq-mode=2 --aq-strength=1.3' instead of '-profile:v main'?
278 Make up for most of the loss of grain and macroblocking
279 with less computing power.
280 */ 352 */
281 353
282 return localCommand 354 return localCommand
283} 355}
284 356
285/** 357/**
286 * A preset optimised for a stillimage audio video
287 */
288async function presetStillImageWithAudio (
289 command: ffmpeg.FfmpegCommand,
290 resolution: VideoResolution,
291 fps: number
292): Promise<ffmpeg.FfmpegCommand> {
293 let localCommand = await presetH264VeryFast(command, resolution, fps)
294 localCommand = localCommand.outputOption('-tune stillimage')
295
296 return localCommand
297}
298
299/**
300 * A toolbox to play with audio 358 * A toolbox to play with audio
301 */ 359 */
302namespace audio { 360namespace audio {
303 export const get = (option: ffmpeg.FfmpegCommand | string) => { 361 export const get = (option: string) => {
304 // without position, ffprobe considers the last input only 362 // without position, ffprobe considers the last input only
305 // we make it consider the first input only 363 // we make it consider the first input only
306 // if you pass a file path to pos, then ffprobe acts on that file directly 364 // if you pass a file path to pos, then ffprobe acts on that file directly
@@ -322,11 +380,7 @@ namespace audio {
322 return res({ absolutePath: data.format.filename }) 380 return res({ absolutePath: data.format.filename })
323 } 381 }
324 382
325 if (typeof option === 'string') { 383 return ffmpeg.ffprobe(option, parseFfprobe)
326 return ffmpeg.ffprobe(option, parseFfprobe)
327 }
328
329 return option.ffprobe(parseFfprobe)
330 }) 384 })
331 } 385 }
332 386
@@ -368,7 +422,7 @@ namespace audio {
368 * As for the audio, quality '5' is the highest and ensures 96-112kbps/channel 422 * As for the audio, quality '5' is the highest and ensures 96-112kbps/channel
369 * See https://trac.ffmpeg.org/wiki/Encode/AAC#fdk_vbr 423 * See https://trac.ffmpeg.org/wiki/Encode/AAC#fdk_vbr
370 */ 424 */
371async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResolution, fps: number): Promise<ffmpeg.FfmpegCommand> { 425async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolution: VideoResolution, fps?: number) {
372 let localCommand = command 426 let localCommand = command
373 .format('mp4') 427 .format('mp4')
374 .videoCodec('libx264') 428 .videoCodec('libx264')
@@ -379,7 +433,7 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResol
379 .outputOption('-map_metadata -1') // strip all metadata 433 .outputOption('-map_metadata -1') // strip all metadata
380 .outputOption('-movflags faststart') 434 .outputOption('-movflags faststart')
381 435
382 const parsedAudio = await audio.get(localCommand) 436 const parsedAudio = await audio.get(input)
383 437
384 if (!parsedAudio.audioStream) { 438 if (!parsedAudio.audioStream) {
385 localCommand = localCommand.noAudio() 439 localCommand = localCommand.noAudio()
@@ -388,28 +442,30 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResol
388 .audioCodec('libfdk_aac') 442 .audioCodec('libfdk_aac')
389 .audioQuality(5) 443 .audioQuality(5)
390 } else { 444 } else {
391 // we try to reduce the ceiling bitrate by making rough correspondances of bitrates 445 // we try to reduce the ceiling bitrate by making rough matches of bitrates
392 // of course this is far from perfect, but it might save some space in the end 446 // of course this is far from perfect, but it might save some space in the end
447 localCommand = localCommand.audioCodec('aac')
448
393 const audioCodecName = parsedAudio.audioStream[ 'codec_name' ] 449 const audioCodecName = parsedAudio.audioStream[ 'codec_name' ]
394 let bitrate: number
395 if (audio.bitrate[ audioCodecName ]) {
396 localCommand = localCommand.audioCodec('aac')
397 450
398 bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ]) 451 if (audio.bitrate[ audioCodecName ]) {
452 const bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ])
399 if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate) 453 if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate)
400 } 454 }
401 } 455 }
402 456
403 // Constrained Encoding (VBV) 457 if (fps) {
404 // https://slhck.info/video/2017/03/01/rate-control.html 458 // Constrained Encoding (VBV)
405 // https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate 459 // https://slhck.info/video/2017/03/01/rate-control.html
406 const targetBitrate = getTargetBitrate(resolution, fps, VIDEO_TRANSCODING_FPS) 460 // https://trac.ffmpeg.org/wiki/Limiting%20the%20output%20bitrate
407 localCommand = localCommand.outputOptions([`-maxrate ${ targetBitrate }`, `-bufsize ${ targetBitrate * 2 }`]) 461 const targetBitrate = getTargetBitrate(resolution, fps, VIDEO_TRANSCODING_FPS)
408 462 localCommand = localCommand.outputOptions([ `-maxrate ${targetBitrate}`, `-bufsize ${targetBitrate * 2}` ])
409 // Keyframe interval of 2 seconds for faster seeking and resolution switching. 463
410 // https://streaminglearningcenter.com/blogs/whats-the-right-keyframe-interval.html 464 // Keyframe interval of 2 seconds for faster seeking and resolution switching.
411 // https://superuser.com/a/908325 465 // https://streaminglearningcenter.com/blogs/whats-the-right-keyframe-interval.html
412 localCommand = localCommand.outputOption(`-g ${ fps * 2 }`) 466 // https://superuser.com/a/908325
467 localCommand = localCommand.outputOption(`-g ${fps * 2}`)
468 }
413 469
414 return localCommand 470 return localCommand
415} 471}
diff --git a/server/initializers/config.ts b/server/initializers/config.ts
index 4f77e144d..2be300a57 100644
--- a/server/initializers/config.ts
+++ b/server/initializers/config.ts
@@ -44,6 +44,14 @@ const CONFIG = {
44 CA_FILE: config.get<string>('smtp.ca_file'), 44 CA_FILE: config.get<string>('smtp.ca_file'),
45 FROM_ADDRESS: config.get<string>('smtp.from_address') 45 FROM_ADDRESS: config.get<string>('smtp.from_address')
46 }, 46 },
47 EMAIL: {
48 BODY: {
49 SIGNATURE: config.get<string>('email.body.signature')
50 },
51 OBJECT: {
52 PREFIX: config.get<string>('email.object.prefix') + ' '
53 }
54 },
47 STORAGE: { 55 STORAGE: {
48 TMP_DIR: buildPath(config.get<string>('storage.tmp')), 56 TMP_DIR: buildPath(config.get<string>('storage.tmp')),
49 AVATARS_DIR: buildPath(config.get<string>('storage.avatars')), 57 AVATARS_DIR: buildPath(config.get<string>('storage.avatars')),
@@ -140,6 +148,7 @@ const CONFIG = {
140 TRANSCODING: { 148 TRANSCODING: {
141 get ENABLED () { return config.get<boolean>('transcoding.enabled') }, 149 get ENABLED () { return config.get<boolean>('transcoding.enabled') },
142 get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') }, 150 get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') },
151 get ALLOW_AUDIO_FILES () { return config.get<boolean>('transcoding.allow_audio_files') },
143 get THREADS () { return config.get<number>('transcoding.threads') }, 152 get THREADS () { return config.get<number>('transcoding.threads') },
144 RESOLUTIONS: { 153 RESOLUTIONS: {
145 get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') }, 154 get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') },
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index b5f8fc0bc..be30be463 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -1,10 +1,10 @@
1import { join } from 'path' 1import { join } from 'path'
2import { JobType, VideoRateType, VideoState } from '../../shared/models' 2import { JobType, VideoRateType, VideoResolution, VideoState } from '../../shared/models'
3import { ActivityPubActorType } from '../../shared/models/activitypub' 3import { ActivityPubActorType } from '../../shared/models/activitypub'
4import { FollowState } from '../../shared/models/actors' 4import { FollowState } from '../../shared/models/actors'
5import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos' 5import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos'
6// Do not use barrels, remain constants as independent as possible 6// Do not use barrels, remain constants as independent as possible
7import { isTestInstance, sanitizeHost, sanitizeUrl } from '../helpers/core-utils' 7import { isTestInstance, sanitizeHost, sanitizeUrl, root } from '../helpers/core-utils'
8import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' 8import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
9import { invert } from 'lodash' 9import { invert } from 'lodash'
10import { CronRepeatOptions, EveryRepeatOptions } from 'bull' 10import { CronRepeatOptions, EveryRepeatOptions } from 'bull'
@@ -14,7 +14,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
14 14
15// --------------------------------------------------------------------------- 15// ---------------------------------------------------------------------------
16 16
17const LAST_MIGRATION_VERSION = 380 17const LAST_MIGRATION_VERSION = 385
18 18
19// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
20 20
@@ -228,7 +228,7 @@ let CONSTRAINTS_FIELDS = {
228 max: 2 * 1024 * 1024 // 2MB 228 max: 2 * 1024 * 1024 // 2MB
229 } 229 }
230 }, 230 },
231 EXTNAME: buildVideosExtname(), 231 EXTNAME: [] as string[],
232 INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2 232 INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2
233 DURATION: { min: 0 }, // Number 233 DURATION: { min: 0 }, // Number
234 TAGS: { min: 0, max: 5 }, // Number of total tags 234 TAGS: { min: 0, max: 5 }, // Number of total tags
@@ -300,6 +300,8 @@ const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = {
300 KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum) 300 KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum)
301} 301}
302 302
303const DEFAULT_AUDIO_RESOLUTION = VideoResolution.H_480P
304
303const VIDEO_RATE_TYPES: { [ id: string ]: VideoRateType } = { 305const VIDEO_RATE_TYPES: { [ id: string ]: VideoRateType } = {
304 LIKE: 'like', 306 LIKE: 'like',
305 DISLIKE: 'dislike' 307 DISLIKE: 'dislike'
@@ -380,8 +382,18 @@ const VIDEO_PLAYLIST_TYPES = {
380} 382}
381 383
382const MIMETYPES = { 384const MIMETYPES = {
385 AUDIO: {
386 MIMETYPE_EXT: {
387 'audio/mpeg': '.mp3',
388 'audio/mp3': '.mp3',
389 'application/ogg': '.ogg',
390 'audio/ogg': '.ogg',
391 'audio/flac': '.flac'
392 },
393 EXT_MIMETYPE: null as { [ id: string ]: string }
394 },
383 VIDEO: { 395 VIDEO: {
384 MIMETYPE_EXT: buildVideoMimetypeExt(), 396 MIMETYPE_EXT: null as { [ id: string ]: string },
385 EXT_MIMETYPE: null as { [ id: string ]: string } 397 EXT_MIMETYPE: null as { [ id: string ]: string }
386 }, 398 },
387 IMAGE: { 399 IMAGE: {
@@ -403,7 +415,7 @@ const MIMETYPES = {
403 } 415 }
404 } 416 }
405} 417}
406MIMETYPES.VIDEO.EXT_MIMETYPE = invert(MIMETYPES.VIDEO.MIMETYPE_EXT) 418MIMETYPES.AUDIO.EXT_MIMETYPE = invert(MIMETYPES.AUDIO.MIMETYPE_EXT)
407 419
408// --------------------------------------------------------------------------- 420// ---------------------------------------------------------------------------
409 421
@@ -429,7 +441,7 @@ const ACTIVITY_PUB = {
429 COLLECTION_ITEMS_PER_PAGE: 10, 441 COLLECTION_ITEMS_PER_PAGE: 10,
430 FETCH_PAGE_LIMIT: 100, 442 FETCH_PAGE_LIMIT: 100,
431 URL_MIME_TYPES: { 443 URL_MIME_TYPES: {
432 VIDEO: Object.keys(MIMETYPES.VIDEO.MIMETYPE_EXT), 444 VIDEO: [] as string[],
433 TORRENT: [ 'application/x-bittorrent' ], 445 TORRENT: [ 'application/x-bittorrent' ],
434 MAGNET: [ 'application/x-bittorrent;x-scheme-handler/magnet' ] 446 MAGNET: [ 'application/x-bittorrent;x-scheme-handler/magnet' ]
435 }, 447 },
@@ -497,8 +509,8 @@ const THUMBNAILS_SIZE = {
497 height: 122 509 height: 122
498} 510}
499const PREVIEWS_SIZE = { 511const PREVIEWS_SIZE = {
500 width: 560, 512 width: 850,
501 height: 315 513 height: 480
502} 514}
503const AVATARS_SIZE = { 515const AVATARS_SIZE = {
504 width: 120, 516 width: 120,
@@ -543,6 +555,10 @@ const REDUNDANCY = {
543 555
544const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS) 556const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS)
545 557
558const ASSETS_PATH = {
559 DEFAULT_AUDIO_BACKGROUND: join(root(), 'server', 'assets', 'default-audio-background.jpg')
560}
561
546// --------------------------------------------------------------------------- 562// ---------------------------------------------------------------------------
547 563
548const CUSTOM_HTML_TAG_COMMENTS = { 564const CUSTOM_HTML_TAG_COMMENTS = {
@@ -612,6 +628,7 @@ if (isTestInstance() === true) {
612} 628}
613 629
614updateWebserverUrls() 630updateWebserverUrls()
631updateWebserverConfig()
615 632
616registerConfigChangedHandler(() => { 633registerConfigChangedHandler(() => {
617 updateWebserverUrls() 634 updateWebserverUrls()
@@ -681,12 +698,14 @@ export {
681 RATES_LIMIT, 698 RATES_LIMIT,
682 MIMETYPES, 699 MIMETYPES,
683 CRAWL_REQUEST_CONCURRENCY, 700 CRAWL_REQUEST_CONCURRENCY,
701 DEFAULT_AUDIO_RESOLUTION,
684 JOB_COMPLETED_LIFETIME, 702 JOB_COMPLETED_LIFETIME,
685 HTTP_SIGNATURE, 703 HTTP_SIGNATURE,
686 VIDEO_IMPORT_STATES, 704 VIDEO_IMPORT_STATES,
687 VIDEO_VIEW_LIFETIME, 705 VIDEO_VIEW_LIFETIME,
688 CONTACT_FORM_LIFETIME, 706 CONTACT_FORM_LIFETIME,
689 VIDEO_PLAYLIST_PRIVACIES, 707 VIDEO_PLAYLIST_PRIVACIES,
708 ASSETS_PATH,
690 loadLanguages, 709 loadLanguages,
691 buildLanguages 710 buildLanguages
692} 711}
@@ -700,15 +719,21 @@ function buildVideoMimetypeExt () {
700 'video/mp4': '.mp4' 719 'video/mp4': '.mp4'
701 } 720 }
702 721
703 if (CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS) { 722 if (CONFIG.TRANSCODING.ENABLED) {
704 Object.assign(data, { 723 if (CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS) {
705 'video/quicktime': '.mov', 724 Object.assign(data, {
706 'video/x-msvideo': '.avi', 725 'video/quicktime': '.mov',
707 'video/x-flv': '.flv', 726 'video/x-msvideo': '.avi',
708 'video/x-matroska': '.mkv', 727 'video/x-flv': '.flv',
709 'application/octet-stream': '.mkv', 728 'video/x-matroska': '.mkv',
710 'video/avi': '.avi' 729 'application/octet-stream': '.mkv',
711 }) 730 'video/avi': '.avi'
731 })
732 }
733
734 if (CONFIG.TRANSCODING.ALLOW_AUDIO_FILES) {
735 Object.assign(data, MIMETYPES.AUDIO.MIMETYPE_EXT)
736 }
712 } 737 }
713 738
714 return data 739 return data
@@ -724,16 +749,15 @@ function updateWebserverUrls () {
724} 749}
725 750
726function updateWebserverConfig () { 751function updateWebserverConfig () {
727 CONSTRAINTS_FIELDS.VIDEOS.EXTNAME = buildVideosExtname()
728
729 MIMETYPES.VIDEO.MIMETYPE_EXT = buildVideoMimetypeExt() 752 MIMETYPES.VIDEO.MIMETYPE_EXT = buildVideoMimetypeExt()
730 MIMETYPES.VIDEO.EXT_MIMETYPE = invert(MIMETYPES.VIDEO.MIMETYPE_EXT) 753 MIMETYPES.VIDEO.EXT_MIMETYPE = invert(MIMETYPES.VIDEO.MIMETYPE_EXT)
754 ACTIVITY_PUB.URL_MIME_TYPES.VIDEO = Object.keys(MIMETYPES.VIDEO.MIMETYPE_EXT)
755
756 CONSTRAINTS_FIELDS.VIDEOS.EXTNAME = buildVideosExtname()
731} 757}
732 758
733function buildVideosExtname () { 759function buildVideosExtname () {
734 return CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS 760 return Object.keys(MIMETYPES.VIDEO.EXT_MIMETYPE)
735 ? [ '.mp4', '.ogv', '.webm', '.mkv', '.mov', '.avi', '.flv' ]
736 : [ '.mp4', '.ogv', '.webm' ]
737} 761}
738 762
739function loadLanguages () { 763function loadLanguages () {
diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts
index 127449577..e14554ede 100644
--- a/server/initializers/installer.ts
+++ b/server/initializers/installer.ts
@@ -128,6 +128,8 @@ async function createOAuthAdminIfNotExist () {
128 128
129 // Our password is weak so do not validate it 129 // Our password is weak so do not validate it
130 validatePassword = false 130 validatePassword = false
131 } else if (process.env.PT_INITIAL_ROOT_PASSWORD) {
132 password = process.env.PT_INITIAL_ROOT_PASSWORD
131 } else { 133 } else {
132 password = passwordGenerator(16, true) 134 password = passwordGenerator(16, true)
133 } 135 }
@@ -144,7 +146,7 @@ async function createOAuthAdminIfNotExist () {
144 } 146 }
145 const user = new UserModel(userData) 147 const user = new UserModel(userData)
146 148
147 await createUserAccountAndChannelAndPlaylist(user, validatePassword) 149 await createUserAccountAndChannelAndPlaylist(user, undefined, validatePassword)
148 logger.info('Username: ' + username) 150 logger.info('Username: ' + username)
149 logger.info('User password: ' + password) 151 logger.info('User password: ' + password)
150} 152}
diff --git a/server/initializers/migrations/0385-remove-actor-uuid.ts b/server/initializers/migrations/0385-remove-actor-uuid.ts
new file mode 100644
index 000000000..032c0562b
--- /dev/null
+++ b/server/initializers/migrations/0385-remove-actor-uuid.ts
@@ -0,0 +1,19 @@
1import * as Sequelize from 'sequelize'
2
3async function up (utils: {
4 transaction: Sequelize.Transaction,
5 queryInterface: Sequelize.QueryInterface,
6 sequelize: Sequelize.Sequelize,
7 db: any
8}): Promise<void> {
9 await utils.queryInterface.removeColumn('actor', 'uuid')
10}
11
12function down (options) {
13 throw new Error('Not implemented.')
14}
15
16export {
17 up,
18 down
19}
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts
index 25cd40905..38eb87d1e 100644
--- a/server/lib/activitypub/actor.ts
+++ b/server/lib/activitypub/actor.ts
@@ -5,7 +5,7 @@ import * as uuidv4 from 'uuid/v4'
5import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' 5import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub'
6import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' 6import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects'
7import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' 7import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
8import { isActorObjectValid, normalizeActor } from '../../helpers/custom-validators/activitypub/actor' 8import { sanitizeAndCheckActorObject } from '../../helpers/custom-validators/activitypub/actor'
9import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' 9import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
10import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' 10import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils'
11import { logger } from '../../helpers/logger' 11import { logger } from '../../helpers/logger'
@@ -33,7 +33,7 @@ function setAsyncActorKeys (actor: ActorModel) {
33 return actor.save() 33 return actor.save()
34 }) 34 })
35 .catch(err => { 35 .catch(err => {
36 logger.error('Cannot set public/private keys of actor %d.', actor.uuid, { err }) 36 logger.error('Cannot set public/private keys of actor %d.', actor.url, { err })
37 return actor 37 return actor
38 }) 38 })
39} 39}
@@ -128,18 +128,17 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ
128 const followersCount = await fetchActorTotalItems(attributes.followers) 128 const followersCount = await fetchActorTotalItems(attributes.followers)
129 const followingCount = await fetchActorTotalItems(attributes.following) 129 const followingCount = await fetchActorTotalItems(attributes.following)
130 130
131 actorInstance.set('type', attributes.type) 131 actorInstance.type = attributes.type
132 actorInstance.set('uuid', attributes.uuid) 132 actorInstance.preferredUsername = attributes.preferredUsername
133 actorInstance.set('preferredUsername', attributes.preferredUsername) 133 actorInstance.url = attributes.id
134 actorInstance.set('url', attributes.id) 134 actorInstance.publicKey = attributes.publicKey.publicKeyPem
135 actorInstance.set('publicKey', attributes.publicKey.publicKeyPem) 135 actorInstance.followersCount = followersCount
136 actorInstance.set('followersCount', followersCount) 136 actorInstance.followingCount = followingCount
137 actorInstance.set('followingCount', followingCount) 137 actorInstance.inboxUrl = attributes.inbox
138 actorInstance.set('inboxUrl', attributes.inbox) 138 actorInstance.outboxUrl = attributes.outbox
139 actorInstance.set('outboxUrl', attributes.outbox) 139 actorInstance.sharedInboxUrl = attributes.endpoints.sharedInbox
140 actorInstance.set('sharedInboxUrl', attributes.endpoints.sharedInbox) 140 actorInstance.followersUrl = attributes.followers
141 actorInstance.set('followersUrl', attributes.followers) 141 actorInstance.followingUrl = attributes.following
142 actorInstance.set('followingUrl', attributes.following)
143} 142}
144 143
145async function updateActorAvatarInstance (actorInstance: ActorModel, avatarName: string, t: Transaction) { 144async function updateActorAvatarInstance (actorInstance: ActorModel, avatarName: string, t: Transaction) {
@@ -370,10 +369,9 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe
370 logger.info('Fetching remote actor %s.', actorUrl) 369 logger.info('Fetching remote actor %s.', actorUrl)
371 370
372 const requestResult = await doRequest<ActivityPubActor>(options) 371 const requestResult = await doRequest<ActivityPubActor>(options)
373 normalizeActor(requestResult.body)
374
375 const actorJSON = requestResult.body 372 const actorJSON = requestResult.body
376 if (isActorObjectValid(actorJSON) === false) { 373
374 if (sanitizeAndCheckActorObject(actorJSON) === false) {
377 logger.debug('Remote actor JSON is not valid.', { actorJSON }) 375 logger.debug('Remote actor JSON is not valid.', { actorJSON })
378 return { result: undefined, statusCode: requestResult.response.statusCode } 376 return { result: undefined, statusCode: requestResult.response.statusCode }
379 } 377 }
@@ -388,7 +386,6 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe
388 386
389 const actor = new ActorModel({ 387 const actor = new ActorModel({
390 type: actorJSON.type, 388 type: actorJSON.type,
391 uuid: actorJSON.uuid,
392 preferredUsername: actorJSON.preferredUsername, 389 preferredUsername: actorJSON.preferredUsername,
393 url: actorJSON.id, 390 url: actorJSON.id,
394 publicKey: actorJSON.publicKey.publicKeyPem, 391 publicKey: actorJSON.publicKey.publicKeyPem,
diff --git a/server/lib/activitypub/crawl.ts b/server/lib/activitypub/crawl.ts
index 686eef04d..9e469e3e6 100644
--- a/server/lib/activitypub/crawl.ts
+++ b/server/lib/activitypub/crawl.ts
@@ -28,13 +28,22 @@ async function crawlCollectionPage <T> (uri: string, handler: HandlerFunction<T>
28 let i = 0 28 let i = 0
29 let nextLink = firstBody.first 29 let nextLink = firstBody.first
30 while (nextLink && i < limit) { 30 while (nextLink && i < limit) {
31 // Don't crawl ourselves 31 let body: any
32 const remoteHost = parse(nextLink).host
33 if (remoteHost === WEBSERVER.HOST) continue
34 32
35 options.uri = nextLink 33 if (typeof nextLink === 'string') {
34 // Don't crawl ourselves
35 const remoteHost = parse(nextLink).host
36 if (remoteHost === WEBSERVER.HOST) continue
37
38 options.uri = nextLink
39
40 const res = await doRequest<ActivityPubOrderedCollection<T>>(options)
41 body = res.body
42 } else {
43 // nextLink is already the object we want
44 body = nextLink
45 }
36 46
37 const { body } = await doRequest<ActivityPubOrderedCollection<T>>(options)
38 nextLink = body.next 47 nextLink = body.next
39 i++ 48 i++
40 49
diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts
index 23310b41e..bbf1bd3a8 100644
--- a/server/lib/activitypub/process/process-announce.ts
+++ b/server/lib/activitypub/process/process-announce.ts
@@ -5,8 +5,9 @@ import { ActorModel } from '../../../models/activitypub/actor'
5import { VideoShareModel } from '../../../models/video/video-share' 5import { VideoShareModel } from '../../../models/video/video-share'
6import { forwardVideoRelatedActivity } from '../send/utils' 6import { forwardVideoRelatedActivity } from '../send/utils'
7import { getOrCreateVideoAndAccountAndChannel } from '../videos' 7import { getOrCreateVideoAndAccountAndChannel } from '../videos'
8import { VideoPrivacy } from '../../../../shared/models/videos'
9import { Notifier } from '../../notifier' 8import { Notifier } from '../../notifier'
9import { VideoModel } from '../../../models/video/video'
10import { logger } from '../../../helpers/logger'
10 11
11async function processAnnounceActivity (activity: ActivityAnnounce, actorAnnouncer: ActorModel) { 12async function processAnnounceActivity (activity: ActivityAnnounce, actorAnnouncer: ActorModel) {
12 return retryTransactionWrapper(processVideoShare, actorAnnouncer, activity) 13 return retryTransactionWrapper(processVideoShare, actorAnnouncer, activity)
@@ -23,7 +24,17 @@ export {
23async function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnounce) { 24async function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnounce) {
24 const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id 25 const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id
25 26
26 const { video, created: videoCreated } = await getOrCreateVideoAndAccountAndChannel({ videoObject: objectUri }) 27 let video: VideoModel
28 let videoCreated: boolean
29
30 try {
31 const result = await getOrCreateVideoAndAccountAndChannel({ videoObject: objectUri })
32 video = result.video
33 videoCreated = result.created
34 } catch (err) {
35 logger.debug('Cannot process share of %s. Maybe this is not a video object, so just skipping.', objectUri, { err })
36 return
37 }
27 38
28 await sequelizeTypescript.transaction(async t => { 39 await sequelizeTypescript.transaction(async t => {
29 // Add share entry 40 // Add share entry
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts
index e882669ce..daf846513 100644
--- a/server/lib/activitypub/process/process-create.ts
+++ b/server/lib/activitypub/process/process-create.ts
@@ -9,28 +9,14 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos'
9import { forwardVideoRelatedActivity } from '../send/utils' 9import { forwardVideoRelatedActivity } from '../send/utils'
10import { createOrUpdateCacheFile } from '../cache-file' 10import { createOrUpdateCacheFile } from '../cache-file'
11import { Notifier } from '../../notifier' 11import { Notifier } from '../../notifier'
12import { processViewActivity } from './process-view'
13import { processDislikeActivity } from './process-dislike'
14import { processFlagActivity } from './process-flag'
15import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' 12import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object'
16import { createOrUpdateVideoPlaylist } from '../playlist' 13import { createOrUpdateVideoPlaylist } from '../playlist'
14import { VideoModel } from '../../../models/video/video'
17 15
18async function processCreateActivity (activity: ActivityCreate, byActor: ActorModel) { 16async function processCreateActivity (activity: ActivityCreate, byActor: ActorModel) {
19 const activityObject = activity.object 17 const activityObject = activity.object
20 const activityType = activityObject.type 18 const activityType = activityObject.type
21 19
22 if (activityType === 'View') {
23 return processViewActivity(activity, byActor)
24 }
25
26 if (activityType === 'Dislike') {
27 return retryTransactionWrapper(processDislikeActivity, activity, byActor)
28 }
29
30 if (activityType === 'Flag') {
31 return retryTransactionWrapper(processFlagActivity, activity, byActor)
32 }
33
34 if (activityType === 'Video') { 20 if (activityType === 'Video') {
35 return processCreateVideo(activity) 21 return processCreateVideo(activity)
36 } 22 }
@@ -91,7 +77,18 @@ async function processCreateVideoComment (activity: ActivityCreate, byActor: Act
91 77
92 if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url) 78 if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url)
93 79
94 const { video } = await resolveThread(commentObject.inReplyTo) 80 let video: VideoModel
81 try {
82 const resolveThreadResult = await resolveThread(commentObject.inReplyTo)
83 video = resolveThreadResult.video
84 } catch (err) {
85 logger.debug(
86 'Cannot process video comment because we could not resolve thread %s. Maybe it was not a video thread, so skip it.',
87 commentObject.inReplyTo,
88 { err }
89 )
90 return
91 }
95 92
96 const { comment, created } = await addVideoComment(video, commentObject.id) 93 const { comment, created } = await addVideoComment(video, commentObject.id)
97 94
diff --git a/server/lib/activitypub/process/process-delete.ts b/server/lib/activitypub/process/process-delete.ts
index 76f07fd8a..6f10a50bd 100644
--- a/server/lib/activitypub/process/process-delete.ts
+++ b/server/lib/activitypub/process/process-delete.ts
@@ -95,23 +95,23 @@ async function processDeleteVideoPlaylist (actor: ActorModel, playlistToDelete:
95} 95}
96 96
97async function processDeleteAccount (accountToRemove: AccountModel) { 97async function processDeleteAccount (accountToRemove: AccountModel) {
98 logger.debug('Removing remote account "%s".', accountToRemove.Actor.uuid) 98 logger.debug('Removing remote account "%s".', accountToRemove.Actor.url)
99 99
100 await sequelizeTypescript.transaction(async t => { 100 await sequelizeTypescript.transaction(async t => {
101 await accountToRemove.destroy({ transaction: t }) 101 await accountToRemove.destroy({ transaction: t })
102 }) 102 })
103 103
104 logger.info('Remote account with uuid %s removed.', accountToRemove.Actor.uuid) 104 logger.info('Remote account %s removed.', accountToRemove.Actor.url)
105} 105}
106 106
107async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelModel) { 107async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelModel) {
108 logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.uuid) 108 logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.url)
109 109
110 await sequelizeTypescript.transaction(async t => { 110 await sequelizeTypescript.transaction(async t => {
111 await videoChannelToRemove.destroy({ transaction: t }) 111 await videoChannelToRemove.destroy({ transaction: t })
112 }) 112 })
113 113
114 logger.info('Remote video channel with uuid %s removed.', videoChannelToRemove.Actor.uuid) 114 logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url)
115} 115}
116 116
117function processDeleteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) { 117function processDeleteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) {
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts
index 54a9234bb..71a16dacc 100644
--- a/server/lib/activitypub/process/process-update.ts
+++ b/server/lib/activitypub/process/process-update.ts
@@ -95,7 +95,7 @@ async function processUpdateCacheFile (byActor: ActorModel, activity: ActivityUp
95async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) { 95async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) {
96 const actorAttributesToUpdate = activity.object as ActivityPubActor 96 const actorAttributesToUpdate = activity.object as ActivityPubActor
97 97
98 logger.debug('Updating remote account "%s".', actorAttributesToUpdate.uuid) 98 logger.debug('Updating remote account "%s".', actorAttributesToUpdate.url)
99 let accountOrChannelInstance: AccountModel | VideoChannelModel 99 let accountOrChannelInstance: AccountModel | VideoChannelModel
100 let actorFieldsSave: object 100 let actorFieldsSave: object
101 let accountOrChannelFieldsSave: object 101 let accountOrChannelFieldsSave: object
@@ -128,7 +128,7 @@ async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate)
128 await accountOrChannelInstance.save({ transaction: t }) 128 await accountOrChannelInstance.save({ transaction: t })
129 }) 129 })
130 130
131 logger.info('Remote account with uuid %s updated', actorAttributesToUpdate.uuid) 131 logger.info('Remote account %s updated', actorAttributesToUpdate.url)
132 } catch (err) { 132 } catch (err) {
133 if (actor !== undefined && actorFieldsSave !== undefined) { 133 if (actor !== undefined && actorFieldsSave !== undefined) {
134 resetSequelizeInstance(actor, actorFieldsSave) 134 resetSequelizeInstance(actor, actorFieldsSave)
diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts
index 18f44d50e..c3fc6b462 100644
--- a/server/lib/activitypub/video-comments.ts
+++ b/server/lib/activitypub/video-comments.ts
@@ -80,7 +80,8 @@ async function addVideoComment (videoInstance: VideoModel, commentUrl: string) {
80 return { comment, created } 80 return { comment, created }
81} 81}
82 82
83async function resolveThread (url: string, comments: VideoCommentModel[] = []) { 83type ResolveThreadResult = Promise<{ video: VideoModel, parents: VideoCommentModel[] }>
84async function resolveThread (url: string, comments: VideoCommentModel[] = []): ResolveThreadResult {
84 // Already have this comment? 85 // Already have this comment?
85 const commentFromDatabase = await VideoCommentModel.loadByUrlAndPopulateReplyAndVideo(url) 86 const commentFromDatabase = await VideoCommentModel.loadByUrlAndPopulateReplyAndVideo(url)
86 if (commentFromDatabase) { 87 if (commentFromDatabase) {
@@ -161,7 +162,6 @@ async function resolveThread (url: string, comments: VideoCommentModel[] = []) {
161 162
162 return resolveThread(body.inReplyTo, comments.concat([ comment ])) 163 return resolveThread(body.inReplyTo, comments.concat([ comment ]))
163 } 164 }
164
165} 165}
166 166
167export { 167export {
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts
index 8c06e9751..c4a5a5853 100644
--- a/server/lib/emailer.ts
+++ b/server/lib/emailer.ts
@@ -100,11 +100,11 @@ class Emailer {
100 `You can view it on ${videoUrl} ` + 100 `You can view it on ${videoUrl} ` +
101 `\n\n` + 101 `\n\n` +
102 `Cheers,\n` + 102 `Cheers,\n` +
103 `PeerTube.` 103 `${CONFIG.EMAIL.BODY.SIGNATURE}`
104 104
105 const emailPayload: EmailPayload = { 105 const emailPayload: EmailPayload = {
106 to, 106 to,
107 subject: channelName + ' just published a new video', 107 subject: CONFIG.EMAIL.OBJECT.PREFIX + channelName + ' just published a new video',
108 text 108 text
109 } 109 }
110 110
@@ -119,11 +119,11 @@ class Emailer {
119 `Your ${followType} ${followingName} has a new subscriber: ${followerName}` + 119 `Your ${followType} ${followingName} has a new subscriber: ${followerName}` +
120 `\n\n` + 120 `\n\n` +
121 `Cheers,\n` + 121 `Cheers,\n` +
122 `PeerTube.` 122 `${CONFIG.EMAIL.BODY.SIGNATURE}`
123 123
124 const emailPayload: EmailPayload = { 124 const emailPayload: EmailPayload = {
125 to, 125 to,
126 subject: 'New follower on your channel ' + followingName, 126 subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New follower on your channel ' + followingName,
127 text 127 text
128 } 128 }
129 129
@@ -137,11 +137,11 @@ class Emailer {
137 `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` + 137 `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` +
138 `\n\n` + 138 `\n\n` +
139 `Cheers,\n` + 139 `Cheers,\n` +
140 `PeerTube.` 140 `${CONFIG.EMAIL.BODY.SIGNATURE}`
141 141
142 const emailPayload: EmailPayload = { 142 const emailPayload: EmailPayload = {
143 to, 143 to,
144 subject: 'New instance follower', 144 subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New instance follower',
145 text 145 text
146 } 146 }
147 147
@@ -157,11 +157,11 @@ class Emailer {
157 `You can view it on ${videoUrl} ` + 157 `You can view it on ${videoUrl} ` +
158 `\n\n` + 158 `\n\n` +
159 `Cheers,\n` + 159 `Cheers,\n` +
160 `PeerTube.` 160 `${CONFIG.EMAIL.BODY.SIGNATURE}`
161 161
162 const emailPayload: EmailPayload = { 162 const emailPayload: EmailPayload = {
163 to, 163 to,
164 subject: `Your video ${video.name} is published`, 164 subject: CONFIG.EMAIL.OBJECT.PREFIX + `Your video ${video.name} is published`,
165 text 165 text
166 } 166 }
167 167
@@ -177,11 +177,11 @@ class Emailer {
177 `You can view the imported video on ${videoUrl} ` + 177 `You can view the imported video on ${videoUrl} ` +
178 `\n\n` + 178 `\n\n` +
179 `Cheers,\n` + 179 `Cheers,\n` +
180 `PeerTube.` 180 `${CONFIG.EMAIL.BODY.SIGNATURE}`
181 181
182 const emailPayload: EmailPayload = { 182 const emailPayload: EmailPayload = {
183 to, 183 to,
184 subject: `Your video import ${videoImport.getTargetIdentifier()} is finished`, 184 subject: CONFIG.EMAIL.OBJECT.PREFIX + `Your video import ${videoImport.getTargetIdentifier()} is finished`,
185 text 185 text
186 } 186 }
187 187
@@ -197,11 +197,11 @@ class Emailer {
197 `See your videos import dashboard for more information: ${importUrl}` + 197 `See your videos import dashboard for more information: ${importUrl}` +
198 `\n\n` + 198 `\n\n` +
199 `Cheers,\n` + 199 `Cheers,\n` +
200 `PeerTube.` 200 `${CONFIG.EMAIL.BODY.SIGNATURE}`
201 201
202 const emailPayload: EmailPayload = { 202 const emailPayload: EmailPayload = {
203 to, 203 to,
204 subject: `Your video import ${videoImport.getTargetIdentifier()} encountered an error`, 204 subject: CONFIG.EMAIL.OBJECT.PREFIX + `Your video import ${videoImport.getTargetIdentifier()} encountered an error`,
205 text 205 text
206 } 206 }
207 207
@@ -219,11 +219,11 @@ class Emailer {
219 `You can view it on ${commentUrl} ` + 219 `You can view it on ${commentUrl} ` +
220 `\n\n` + 220 `\n\n` +
221 `Cheers,\n` + 221 `Cheers,\n` +
222 `PeerTube.` 222 `${CONFIG.EMAIL.BODY.SIGNATURE}`
223 223
224 const emailPayload: EmailPayload = { 224 const emailPayload: EmailPayload = {
225 to, 225 to,
226 subject: 'New comment on your video ' + video.name, 226 subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New comment on your video ' + video.name,
227 text 227 text
228 } 228 }
229 229
@@ -241,11 +241,11 @@ class Emailer {
241 `You can view the comment on ${commentUrl} ` + 241 `You can view the comment on ${commentUrl} ` +
242 `\n\n` + 242 `\n\n` +
243 `Cheers,\n` + 243 `Cheers,\n` +
244 `PeerTube.` 244 `${CONFIG.EMAIL.BODY.SIGNATURE}`
245 245
246 const emailPayload: EmailPayload = { 246 const emailPayload: EmailPayload = {
247 to, 247 to,
248 subject: 'Mention on video ' + video.name, 248 subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Mention on video ' + video.name,
249 text 249 text
250 } 250 }
251 251
@@ -258,11 +258,11 @@ class Emailer {
258 const text = `Hi,\n\n` + 258 const text = `Hi,\n\n` +
259 `${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` + 259 `${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` +
260 `Cheers,\n` + 260 `Cheers,\n` +
261 `PeerTube.` 261 `${CONFIG.EMAIL.BODY.SIGNATURE}`
262 262
263 const emailPayload: EmailPayload = { 263 const emailPayload: EmailPayload = {
264 to, 264 to,
265 subject: '[PeerTube] Received a video abuse', 265 subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Received a video abuse',
266 text 266 text
267 } 267 }
268 268
@@ -281,11 +281,11 @@ class Emailer {
281 `A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` + 281 `A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` +
282 `\n\n` + 282 `\n\n` +
283 `Cheers,\n` + 283 `Cheers,\n` +
284 `PeerTube.` 284 `${CONFIG.EMAIL.BODY.SIGNATURE}`
285 285
286 const emailPayload: EmailPayload = { 286 const emailPayload: EmailPayload = {
287 to, 287 to,
288 subject: '[PeerTube] An auto-blacklisted video is awaiting review', 288 subject: CONFIG.EMAIL.OBJECT.PREFIX + 'An auto-blacklisted video is awaiting review',
289 text 289 text
290 } 290 }
291 291
@@ -296,11 +296,11 @@ class Emailer {
296 const text = `Hi,\n\n` + 296 const text = `Hi,\n\n` +
297 `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` + 297 `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` +
298 `Cheers,\n` + 298 `Cheers,\n` +
299 `PeerTube.` 299 `${CONFIG.EMAIL.BODY.SIGNATURE}`
300 300
301 const emailPayload: EmailPayload = { 301 const emailPayload: EmailPayload = {
302 to, 302 to,
303 subject: '[PeerTube] New user registration on ' + WEBSERVER.HOST, 303 subject: CONFIG.EMAIL.OBJECT.PREFIX + 'New user registration on ' + WEBSERVER.HOST,
304 text 304 text
305 } 305 }
306 306
@@ -318,11 +318,11 @@ class Emailer {
318 blockedString + 318 blockedString +
319 '\n\n' + 319 '\n\n' +
320 'Cheers,\n' + 320 'Cheers,\n' +
321 `PeerTube.` 321 `${CONFIG.EMAIL.BODY.SIGNATURE}`
322 322
323 const emailPayload: EmailPayload = { 323 const emailPayload: EmailPayload = {
324 to, 324 to,
325 subject: `[PeerTube] Video ${videoName} blacklisted`, 325 subject: CONFIG.EMAIL.OBJECT.PREFIX + `Video ${videoName} blacklisted`,
326 text 326 text
327 } 327 }
328 328
@@ -336,11 +336,11 @@ class Emailer {
336 `Your video ${video.name} (${videoUrl}) on ${WEBSERVER.HOST} has been unblacklisted.` + 336 `Your video ${video.name} (${videoUrl}) on ${WEBSERVER.HOST} has been unblacklisted.` +
337 '\n\n' + 337 '\n\n' +
338 'Cheers,\n' + 338 'Cheers,\n' +
339 `PeerTube.` 339 `${CONFIG.EMAIL.BODY.SIGNATURE}`
340 340
341 const emailPayload: EmailPayload = { 341 const emailPayload: EmailPayload = {
342 to, 342 to,
343 subject: `[PeerTube] Video ${video.name} unblacklisted`, 343 subject: CONFIG.EMAIL.OBJECT.PREFIX + `Video ${video.name} unblacklisted`,
344 text 344 text
345 } 345 }
346 346
@@ -353,11 +353,11 @@ class Emailer {
353 `Please follow this link to reset it: ${resetPasswordUrl}\n\n` + 353 `Please follow this link to reset it: ${resetPasswordUrl}\n\n` +
354 `If you are not the person who initiated this request, please ignore this email.\n\n` + 354 `If you are not the person who initiated this request, please ignore this email.\n\n` +
355 `Cheers,\n` + 355 `Cheers,\n` +
356 `PeerTube.` 356 `${CONFIG.EMAIL.BODY.SIGNATURE}`
357 357
358 const emailPayload: EmailPayload = { 358 const emailPayload: EmailPayload = {
359 to: [ to ], 359 to: [ to ],
360 subject: 'Reset your PeerTube password', 360 subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Reset your password',
361 text 361 text
362 } 362 }
363 363
@@ -370,11 +370,11 @@ class Emailer {
370 `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` + 370 `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` +
371 `If you are not the person who initiated this request, please ignore this email.\n\n` + 371 `If you are not the person who initiated this request, please ignore this email.\n\n` +
372 `Cheers,\n` + 372 `Cheers,\n` +
373 `PeerTube.` 373 `${CONFIG.EMAIL.BODY.SIGNATURE}`
374 374
375 const emailPayload: EmailPayload = { 375 const emailPayload: EmailPayload = {
376 to: [ to ], 376 to: [ to ],
377 subject: 'Verify your PeerTube email', 377 subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Verify your email',
378 text 378 text
379 } 379 }
380 380
@@ -390,12 +390,12 @@ class Emailer {
390 blockedString + 390 blockedString +
391 '\n\n' + 391 '\n\n' +
392 'Cheers,\n' + 392 'Cheers,\n' +
393 `PeerTube.` 393 `${CONFIG.EMAIL.BODY.SIGNATURE}`
394 394
395 const to = user.email 395 const to = user.email
396 const emailPayload: EmailPayload = { 396 const emailPayload: EmailPayload = {
397 to: [ to ], 397 to: [ to ],
398 subject: '[PeerTube] Account ' + blockedWord, 398 subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Account ' + blockedWord,
399 text 399 text
400 } 400 }
401 401
@@ -415,7 +415,7 @@ class Emailer {
415 fromDisplayName: fromEmail, 415 fromDisplayName: fromEmail,
416 replyTo: fromEmail, 416 replyTo: fromEmail,
417 to: [ CONFIG.ADMIN.EMAIL ], 417 to: [ CONFIG.ADMIN.EMAIL ],
418 subject: '[PeerTube] Contact form submitted', 418 subject: CONFIG.EMAIL.OBJECT.PREFIX + 'Contact form submitted',
419 text 419 text
420 } 420 }
421 421
diff --git a/server/lib/files-cache/videos-preview-cache.ts b/server/lib/files-cache/videos-preview-cache.ts
index 14be7f24a..a68619d07 100644
--- a/server/lib/files-cache/videos-preview-cache.ts
+++ b/server/lib/files-cache/videos-preview-cache.ts
@@ -21,7 +21,7 @@ class VideosPreviewCache extends AbstractVideoStaticFileCache <string> {
21 const video = await VideoModel.loadByUUIDWithFile(videoUUID) 21 const video = await VideoModel.loadByUUIDWithFile(videoUUID)
22 if (!video) return undefined 22 if (!video) return undefined
23 23
24 if (video.isOwned()) return { isOwned: true, path: join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreview().filename) } 24 if (video.isOwned()) return { isOwned: true, path: video.getPreview().getPath() }
25 25
26 return this.loadRemoteFile(videoUUID) 26 return this.loadRemoteFile(videoUUID)
27 } 27 }
diff --git a/server/lib/job-queue/handlers/video-file-import.ts b/server/lib/job-queue/handlers/video-file-import.ts
index 921d9a083..8cacb0ef3 100644
--- a/server/lib/job-queue/handlers/video-file-import.ts
+++ b/server/lib/job-queue/handlers/video-file-import.ts
@@ -1,7 +1,7 @@
1import * as Bull from 'bull' 1import * as Bull from 'bull'
2import { logger } from '../../../helpers/logger' 2import { logger } from '../../../helpers/logger'
3import { VideoModel } from '../../../models/video/video' 3import { VideoModel } from '../../../models/video/video'
4import { publishVideoIfNeeded } from './video-transcoding' 4import { publishNewResolutionIfNeeded } from './video-transcoding'
5import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' 5import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
6import { copy, stat } from 'fs-extra' 6import { copy, stat } from 'fs-extra'
7import { VideoFileModel } from '../../../models/video/video-file' 7import { VideoFileModel } from '../../../models/video/video-file'
@@ -25,7 +25,7 @@ async function processVideoFileImport (job: Bull.Job) {
25 25
26 await updateVideoFile(video, payload.filePath) 26 await updateVideoFile(video, payload.filePath)
27 27
28 await publishVideoIfNeeded(video) 28 await publishNewResolutionIfNeeded(video)
29 return video 29 return video
30} 30}
31 31
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts
index 1650916a6..50e159245 100644
--- a/server/lib/job-queue/handlers/video-import.ts
+++ b/server/lib/job-queue/handlers/video-import.ts
@@ -209,6 +209,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: Vide
209 if (videoImportUpdated.Video.state === VideoState.TO_TRANSCODE) { 209 if (videoImportUpdated.Video.state === VideoState.TO_TRANSCODE) {
210 // Put uuid because we don't have id auto incremented for now 210 // Put uuid because we don't have id auto incremented for now
211 const dataInput = { 211 const dataInput = {
212 type: 'optimize' as 'optimize',
212 videoUUID: videoImportUpdated.Video.uuid, 213 videoUUID: videoImportUpdated.Video.uuid,
213 isNewVideo: true 214 isNewVideo: true
214 } 215 }
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts
index 48cac517e..e9b84ecd6 100644
--- a/server/lib/job-queue/handlers/video-transcoding.ts
+++ b/server/lib/job-queue/handlers/video-transcoding.ts
@@ -8,18 +8,39 @@ import { retryTransactionWrapper } from '../../../helpers/database-utils'
8import { sequelizeTypescript } from '../../../initializers' 8import { sequelizeTypescript } from '../../../initializers'
9import * as Bluebird from 'bluebird' 9import * as Bluebird from 'bluebird'
10import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' 10import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils'
11import { generateHlsPlaylist, optimizeVideofile, transcodeOriginalVideofile } from '../../video-transcoding' 11import { generateHlsPlaylist, optimizeVideofile, transcodeOriginalVideofile, mergeAudioVideofile } from '../../video-transcoding'
12import { Notifier } from '../../notifier' 12import { Notifier } from '../../notifier'
13import { CONFIG } from '../../../initializers/config' 13import { CONFIG } from '../../../initializers/config'
14 14
15export type VideoTranscodingPayload = { 15interface BaseTranscodingPayload {
16 videoUUID: string 16 videoUUID: string
17 resolution?: VideoResolution
18 isNewVideo?: boolean 17 isNewVideo?: boolean
18}
19
20interface HLSTranscodingPayload extends BaseTranscodingPayload {
21 type: 'hls'
22 isPortraitMode?: boolean
23 resolution: VideoResolution
24}
25
26interface NewResolutionTranscodingPayload extends BaseTranscodingPayload {
27 type: 'new-resolution'
19 isPortraitMode?: boolean 28 isPortraitMode?: boolean
20 generateHlsPlaylist?: boolean 29 resolution: VideoResolution
30}
31
32interface MergeAudioTranscodingPayload extends BaseTranscodingPayload {
33 type: 'merge-audio'
34 resolution: VideoResolution
35}
36
37interface OptimizeTranscodingPayload extends BaseTranscodingPayload {
38 type: 'optimize'
21} 39}
22 40
41export type VideoTranscodingPayload = HLSTranscodingPayload | NewResolutionTranscodingPayload
42 | OptimizeTranscodingPayload | MergeAudioTranscodingPayload
43
23async function processVideoTranscoding (job: Bull.Job) { 44async function processVideoTranscoding (job: Bull.Job) {
24 const payload = job.data as VideoTranscodingPayload 45 const payload = job.data as VideoTranscodingPayload
25 logger.info('Processing video file in job %d.', job.id) 46 logger.info('Processing video file in job %d.', job.id)
@@ -31,14 +52,18 @@ async function processVideoTranscoding (job: Bull.Job) {
31 return undefined 52 return undefined
32 } 53 }
33 54
34 if (payload.generateHlsPlaylist) { 55 if (payload.type === 'hls') {
35 await generateHlsPlaylist(video, payload.resolution, payload.isPortraitMode || false) 56 await generateHlsPlaylist(video, payload.resolution, payload.isPortraitMode || false)
36 57
37 await retryTransactionWrapper(onHlsPlaylistGenerationSuccess, video) 58 await retryTransactionWrapper(onHlsPlaylistGenerationSuccess, video)
38 } else if (payload.resolution) { // Transcoding in other resolution 59 } else if (payload.type === 'new-resolution') {
39 await transcodeOriginalVideofile(video, payload.resolution, payload.isPortraitMode || false) 60 await transcodeOriginalVideofile(video, payload.resolution, payload.isPortraitMode || false)
40 61
41 await retryTransactionWrapper(publishVideoIfNeeded, video, payload) 62 await retryTransactionWrapper(publishNewResolutionIfNeeded, video, payload)
63 } else if (payload.type === 'merge-audio') {
64 await mergeAudioVideofile(video, payload.resolution)
65
66 await retryTransactionWrapper(publishNewResolutionIfNeeded, video, payload)
42 } else { 67 } else {
43 await optimizeVideofile(video) 68 await optimizeVideofile(video)
44 69
@@ -62,7 +87,7 @@ async function onHlsPlaylistGenerationSuccess (video: VideoModel) {
62 }) 87 })
63} 88}
64 89
65async function publishVideoIfNeeded (video: VideoModel, payload?: VideoTranscodingPayload) { 90async function publishNewResolutionIfNeeded (video: VideoModel, payload?: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload) {
66 const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => { 91 const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => {
67 // Maybe the video changed in database, refresh it 92 // Maybe the video changed in database, refresh it
68 let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t) 93 let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t)
@@ -94,7 +119,7 @@ async function publishVideoIfNeeded (video: VideoModel, payload?: VideoTranscodi
94 await createHlsJobIfEnabled(payload) 119 await createHlsJobIfEnabled(payload)
95} 120}
96 121
97async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: VideoTranscodingPayload) { 122async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: OptimizeTranscodingPayload) {
98 if (videoArg === undefined) return undefined 123 if (videoArg === undefined) return undefined
99 124
100 // Outside the transaction (IO on disk) 125 // Outside the transaction (IO on disk)
@@ -120,6 +145,7 @@ async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: Video
120 145
121 for (const resolution of resolutionsEnabled) { 146 for (const resolution of resolutionsEnabled) {
122 const dataInput = { 147 const dataInput = {
148 type: 'new-resolution' as 'new-resolution',
123 videoUUID: videoDatabase.uuid, 149 videoUUID: videoDatabase.uuid,
124 resolution 150 resolution
125 } 151 }
@@ -149,27 +175,27 @@ async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: Video
149 if (payload.isNewVideo) Notifier.Instance.notifyOnNewVideo(videoDatabase) 175 if (payload.isNewVideo) Notifier.Instance.notifyOnNewVideo(videoDatabase)
150 if (videoPublished) Notifier.Instance.notifyOnVideoPublishedAfterTranscoding(videoDatabase) 176 if (videoPublished) Notifier.Instance.notifyOnVideoPublishedAfterTranscoding(videoDatabase)
151 177
152 await createHlsJobIfEnabled(Object.assign({}, payload, { resolution: videoDatabase.getOriginalFile().resolution })) 178 const hlsPayload = Object.assign({}, payload, { resolution: videoDatabase.getOriginalFile().resolution })
179 await createHlsJobIfEnabled(hlsPayload)
153} 180}
154 181
155// --------------------------------------------------------------------------- 182// ---------------------------------------------------------------------------
156 183
157export { 184export {
158 processVideoTranscoding, 185 processVideoTranscoding,
159 publishVideoIfNeeded 186 publishNewResolutionIfNeeded
160} 187}
161 188
162// --------------------------------------------------------------------------- 189// ---------------------------------------------------------------------------
163 190
164function createHlsJobIfEnabled (payload?: VideoTranscodingPayload) { 191function createHlsJobIfEnabled (payload?: { videoUUID: string, resolution: number, isPortraitMode?: boolean }) {
165 // Generate HLS playlist? 192 // Generate HLS playlist?
166 if (payload && CONFIG.TRANSCODING.HLS.ENABLED) { 193 if (payload && CONFIG.TRANSCODING.HLS.ENABLED) {
167 const hlsTranscodingPayload = { 194 const hlsTranscodingPayload = {
195 type: 'hls' as 'hls',
168 videoUUID: payload.videoUUID, 196 videoUUID: payload.videoUUID,
169 resolution: payload.resolution, 197 resolution: payload.resolution,
170 isPortraitMode: payload.isPortraitMode, 198 isPortraitMode: payload.isPortraitMode
171
172 generateHlsPlaylist: true
173 } 199 }
174 200
175 return JobQueue.Instance.createJob({ type: 'video-transcoding', payload: hlsTranscodingPayload }) 201 return JobQueue.Instance.createJob({ type: 'video-transcoding', payload: hlsTranscodingPayload })
diff --git a/server/lib/thumbnail.ts b/server/lib/thumbnail.ts
index 950b14c3b..18bdcded4 100644
--- a/server/lib/thumbnail.ts
+++ b/server/lib/thumbnail.ts
@@ -1,7 +1,7 @@
1import { VideoFileModel } from '../models/video/video-file' 1import { VideoFileModel } from '../models/video/video-file'
2import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils' 2import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils'
3import { CONFIG } from '../initializers/config' 3import { CONFIG } from '../initializers/config'
4import { PREVIEWS_SIZE, THUMBNAILS_SIZE } from '../initializers/constants' 4import { PREVIEWS_SIZE, THUMBNAILS_SIZE, ASSETS_PATH } from '../initializers/constants'
5import { VideoModel } from '../models/video/video' 5import { VideoModel } from '../models/video/video'
6import { ThumbnailModel } from '../models/video/thumbnail' 6import { ThumbnailModel } from '../models/video/thumbnail'
7import { ThumbnailType } from '../../shared/models/videos/thumbnail.type' 7import { ThumbnailType } from '../../shared/models/videos/thumbnail.type'
@@ -45,8 +45,10 @@ function createVideoMiniatureFromExisting (inputPath: string, video: VideoModel,
45function generateVideoMiniature (video: VideoModel, videoFile: VideoFileModel, type: ThumbnailType) { 45function generateVideoMiniature (video: VideoModel, videoFile: VideoFileModel, type: ThumbnailType) {
46 const input = video.getVideoFilePath(videoFile) 46 const input = video.getVideoFilePath(videoFile)
47 47
48 const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type) 48 const { filename, basePath, height, width, existingThumbnail, outputPath } = buildMetadataFromVideo(video, type)
49 const thumbnailCreator = () => generateImageFromVideoFile(input, basePath, filename, { height, width }) 49 const thumbnailCreator = videoFile.isAudio()
50 ? () => processImage(ASSETS_PATH.DEFAULT_AUDIO_BACKGROUND, outputPath, { width, height }, true)
51 : () => generateImageFromVideoFile(input, basePath, filename, { height, width })
50 52
51 return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail }) 53 return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail })
52} 54}
diff --git a/server/lib/user.ts b/server/lib/user.ts
index 7badb3e72..d9fd89e15 100644
--- a/server/lib/user.ts
+++ b/server/lib/user.ts
@@ -13,7 +13,8 @@ import { UserNotificationSetting, UserNotificationSettingValue } from '../../sha
13import { createWatchLaterPlaylist } from './video-playlist' 13import { createWatchLaterPlaylist } from './video-playlist'
14import { sequelizeTypescript } from '../initializers/database' 14import { sequelizeTypescript } from '../initializers/database'
15 15
16async function createUserAccountAndChannelAndPlaylist (userToCreate: UserModel, validateUser = true) { 16type ChannelNames = { name: string, displayName: string }
17async function createUserAccountAndChannelAndPlaylist (userToCreate: UserModel, channelNames?: ChannelNames, validateUser = true) {
17 const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => { 18 const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => {
18 const userOptions = { 19 const userOptions = {
19 transaction: t, 20 transaction: t,
@@ -26,18 +27,8 @@ async function createUserAccountAndChannelAndPlaylist (userToCreate: UserModel,
26 const accountCreated = await createLocalAccountWithoutKeys(userCreated.username, userCreated.id, null, t) 27 const accountCreated = await createLocalAccountWithoutKeys(userCreated.username, userCreated.id, null, t)
27 userCreated.Account = accountCreated 28 userCreated.Account = accountCreated
28 29
29 let channelName = userCreated.username + '_channel' 30 const channelAttributes = await buildChannelAttributes(userCreated, channelNames)
30 31 const videoChannel = await createVideoChannel(channelAttributes, accountCreated, t)
31 // Conflict, generate uuid instead
32 const actor = await ActorModel.loadLocalByName(channelName)
33 if (actor) channelName = uuidv4()
34
35 const videoChannelDisplayName = `Main ${userCreated.username} channel`
36 const videoChannelInfo = {
37 name: channelName,
38 displayName: videoChannelDisplayName
39 }
40 const videoChannel = await createVideoChannel(videoChannelInfo, accountCreated, t)
41 32
42 const videoPlaylist = await createWatchLaterPlaylist(accountCreated, t) 33 const videoPlaylist = await createWatchLaterPlaylist(accountCreated, t)
43 34
@@ -116,3 +107,20 @@ function createDefaultUserNotificationSettings (user: UserModel, t: Sequelize.Tr
116 107
117 return UserNotificationSettingModel.create(values, { transaction: t }) 108 return UserNotificationSettingModel.create(values, { transaction: t })
118} 109}
110
111async function buildChannelAttributes (user: UserModel, channelNames?: ChannelNames) {
112 if (channelNames) return channelNames
113
114 let channelName = user.username + '_channel'
115
116 // Conflict, generate uuid instead
117 const actor = await ActorModel.loadLocalByName(channelName)
118 if (actor) channelName = uuidv4()
119
120 const videoChannelDisplayName = `Main ${user.username} channel`
121
122 return {
123 name: channelName,
124 displayName: videoChannelDisplayName
125 }
126}
diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts
index 0fe95ca09..ee0482c36 100644
--- a/server/lib/video-channel.ts
+++ b/server/lib/video-channel.ts
@@ -3,7 +3,8 @@ import * as uuidv4 from 'uuid/v4'
3import { VideoChannelCreate } from '../../shared/models' 3import { VideoChannelCreate } from '../../shared/models'
4import { AccountModel } from '../models/account/account' 4import { AccountModel } from '../models/account/account'
5import { VideoChannelModel } from '../models/video/video-channel' 5import { VideoChannelModel } from '../models/video/video-channel'
6import { buildActorInstance, getVideoChannelActivityPubUrl } from './activitypub' 6import { buildActorInstance, federateVideoIfNeeded, getVideoChannelActivityPubUrl } from './activitypub'
7import { VideoModel } from '../models/video/video'
7 8
8async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountModel, t: Sequelize.Transaction) { 9async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountModel, t: Sequelize.Transaction) {
9 const uuid = uuidv4() 10 const uuid = uuidv4()
@@ -33,8 +34,19 @@ async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account
33 return videoChannelCreated 34 return videoChannelCreated
34} 35}
35 36
37async function federateAllVideosOfChannel (videoChannel: VideoChannelModel) {
38 const videoIds = await VideoModel.getAllIdsFromChannel(videoChannel)
39
40 for (const videoId of videoIds) {
41 const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoId)
42
43 await federateVideoIfNeeded(video, false)
44 }
45}
46
36// --------------------------------------------------------------------------- 47// ---------------------------------------------------------------------------
37 48
38export { 49export {
39 createVideoChannel 50 createVideoChannel,
51 federateAllVideosOfChannel
40} 52}
diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts
index 0fe0ff12a..8d786e0ef 100644
--- a/server/lib/video-transcoding.ts
+++ b/server/lib/video-transcoding.ts
@@ -1,6 +1,6 @@
1import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../initializers/constants' 1import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../initializers/constants'
2import { join } from 'path' 2import { join } from 'path'
3import { getVideoFileFPS, transcode } from '../helpers/ffmpeg-utils' 3import { canDoQuickTranscode, getVideoFileFPS, transcode, TranscodeOptions, TranscodeOptionsType } from '../helpers/ffmpeg-utils'
4import { ensureDir, move, remove, stat } from 'fs-extra' 4import { ensureDir, move, remove, stat } from 'fs-extra'
5import { logger } from '../helpers/logger' 5import { logger } from '../helpers/logger'
6import { VideoResolution } from '../../shared/models/videos' 6import { VideoResolution } from '../../shared/models/videos'
@@ -11,15 +11,24 @@ import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-pla
11import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' 11import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type'
12import { CONFIG } from '../initializers/config' 12import { CONFIG } from '../initializers/config'
13 13
14/**
15 * Optimize the original video file and replace it. The resolution is not changed.
16 */
14async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFileModel) { 17async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFileModel) {
15 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR 18 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
19 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
16 const newExtname = '.mp4' 20 const newExtname = '.mp4'
17 21
18 const inputVideoFile = inputVideoFileArg ? inputVideoFileArg : video.getOriginalFile() 22 const inputVideoFile = inputVideoFileArg ? inputVideoFileArg : video.getOriginalFile()
19 const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile)) 23 const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile))
20 const videoTranscodedPath = join(videosDirectory, video.id + '-transcoded' + newExtname) 24 const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname)
21 25
22 const transcodeOptions = { 26 const transcodeType: TranscodeOptionsType = await canDoQuickTranscode(videoInputPath)
27 ? 'quick-transcode'
28 : 'video'
29
30 const transcodeOptions: TranscodeOptions = {
31 type: transcodeType as any, // FIXME: typing issue
23 inputPath: videoInputPath, 32 inputPath: videoInputPath,
24 outputPath: videoTranscodedPath, 33 outputPath: videoTranscodedPath,
25 resolution: inputVideoFile.resolution 34 resolution: inputVideoFile.resolution
@@ -32,18 +41,11 @@ async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFi
32 await remove(videoInputPath) 41 await remove(videoInputPath)
33 42
34 // Important to do this before getVideoFilename() to take in account the new file extension 43 // Important to do this before getVideoFilename() to take in account the new file extension
35 inputVideoFile.set('extname', newExtname) 44 inputVideoFile.extname = newExtname
36 45
37 const videoOutputPath = video.getVideoFilePath(inputVideoFile) 46 const videoOutputPath = video.getVideoFilePath(inputVideoFile)
38 await move(videoTranscodedPath, videoOutputPath)
39 const stats = await stat(videoOutputPath)
40 const fps = await getVideoFileFPS(videoOutputPath)
41 47
42 inputVideoFile.set('size', stats.size) 48 await onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath)
43 inputVideoFile.set('fps', fps)
44
45 await video.createTorrentAndSetInfoHash(inputVideoFile)
46 await inputVideoFile.save()
47 } catch (err) { 49 } catch (err) {
48 // Auto destruction... 50 // Auto destruction...
49 video.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', { err })) 51 video.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', { err }))
@@ -52,8 +54,12 @@ async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFi
52 } 54 }
53} 55}
54 56
57/**
58 * Transcode the original video file to a lower resolution.
59 */
55async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoResolution, isPortrait: boolean) { 60async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoResolution, isPortrait: boolean) {
56 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR 61 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
62 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
57 const extname = '.mp4' 63 const extname = '.mp4'
58 64
59 // We are sure it's x264 in mp4 because optimizeOriginalVideofile was already executed 65 // We are sure it's x264 in mp4 because optimizeOriginalVideofile was already executed
@@ -66,27 +72,49 @@ async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoR
66 videoId: video.id 72 videoId: video.id
67 }) 73 })
68 const videoOutputPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename(newVideoFile)) 74 const videoOutputPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename(newVideoFile))
75 const videoTranscodedPath = join(transcodeDirectory, video.getVideoFilename(newVideoFile))
69 76
70 const transcodeOptions = { 77 const transcodeOptions = {
78 type: 'video' as 'video',
71 inputPath: videoInputPath, 79 inputPath: videoInputPath,
72 outputPath: videoOutputPath, 80 outputPath: videoTranscodedPath,
73 resolution, 81 resolution,
74 isPortraitMode: isPortrait 82 isPortraitMode: isPortrait
75 } 83 }
76 84
77 await transcode(transcodeOptions) 85 await transcode(transcodeOptions)
78 86
79 const stats = await stat(videoOutputPath) 87 return onVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath)
80 const fps = await getVideoFileFPS(videoOutputPath) 88}
89
90async function mergeAudioVideofile (video: VideoModel, resolution: VideoResolution) {
91 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
92 const transcodeDirectory = CONFIG.STORAGE.TMP_DIR
93 const newExtname = '.mp4'
94
95 const inputVideoFile = video.getOriginalFile()
81 96
82 newVideoFile.set('size', stats.size) 97 const audioInputPath = join(videosDirectory, video.getVideoFilename(video.getOriginalFile()))
83 newVideoFile.set('fps', fps) 98 const videoTranscodedPath = join(transcodeDirectory, video.id + '-transcoded' + newExtname)
84 99
85 await video.createTorrentAndSetInfoHash(newVideoFile) 100 const transcodeOptions = {
101 type: 'merge-audio' as 'merge-audio',
102 inputPath: video.getPreview().getPath(),
103 outputPath: videoTranscodedPath,
104 audioPath: audioInputPath,
105 resolution
106 }
107
108 await transcode(transcodeOptions)
86 109
87 await newVideoFile.save() 110 await remove(audioInputPath)
88 111
89 video.VideoFiles.push(newVideoFile) 112 // Important to do this before getVideoFilename() to take in account the new file extension
113 inputVideoFile.extname = newExtname
114
115 const videoOutputPath = video.getVideoFilePath(inputVideoFile)
116
117 return onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath)
90} 118}
91 119
92async function generateHlsPlaylist (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) { 120async function generateHlsPlaylist (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) {
@@ -97,6 +125,7 @@ async function generateHlsPlaylist (video: VideoModel, resolution: VideoResoluti
97 const outputPath = join(baseHlsDirectory, VideoStreamingPlaylistModel.getHlsPlaylistFilename(resolution)) 125 const outputPath = join(baseHlsDirectory, VideoStreamingPlaylistModel.getHlsPlaylistFilename(resolution))
98 126
99 const transcodeOptions = { 127 const transcodeOptions = {
128 type: 'hls' as 'hls',
100 inputPath: videoInputPath, 129 inputPath: videoInputPath,
101 outputPath, 130 outputPath,
102 resolution, 131 resolution,
@@ -125,8 +154,34 @@ async function generateHlsPlaylist (video: VideoModel, resolution: VideoResoluti
125 }) 154 })
126} 155}
127 156
157// ---------------------------------------------------------------------------
158
128export { 159export {
129 generateHlsPlaylist, 160 generateHlsPlaylist,
130 optimizeVideofile, 161 optimizeVideofile,
131 transcodeOriginalVideofile 162 transcodeOriginalVideofile,
163 mergeAudioVideofile
164}
165
166// ---------------------------------------------------------------------------
167
168async function onVideoFileTranscoding (video: VideoModel, videoFile: VideoFileModel, transcodingPath: string, outputPath: string) {
169 const stats = await stat(transcodingPath)
170 const fps = await getVideoFileFPS(transcodingPath)
171
172 await move(transcodingPath, outputPath)
173
174 videoFile.set('size', stats.size)
175 videoFile.set('fps', fps)
176
177 await video.createTorrentAndSetInfoHash(videoFile)
178
179 const updatedVideoFile = await videoFile.save()
180
181 // Add it if this is a new created file
182 if (video.VideoFiles.some(f => f.id === videoFile.id) === false) {
183 video.VideoFiles.push(updatedVideoFile)
184 }
185
186 return video
132} 187}
diff --git a/server/middlewares/validators/feeds.ts b/server/middlewares/validators/feeds.ts
index e4f5c98fe..dd362619d 100644
--- a/server/middlewares/validators/feeds.ts
+++ b/server/middlewares/validators/feeds.ts
@@ -1,21 +1,20 @@
1import * as express from 'express' 1import * as express from 'express'
2import { param, query } from 'express-validator/check' 2import { param, query } from 'express-validator/check'
3import { doesAccountIdExist, isAccountNameValid, doesAccountNameWithHostExist } from '../../helpers/custom-validators/accounts' 3import { doesAccountIdExist, doesAccountNameWithHostExist } from '../../helpers/custom-validators/accounts'
4import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' 4import { isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc'
5import { logger } from '../../helpers/logger' 5import { logger } from '../../helpers/logger'
6import { areValidationErrors } from './utils' 6import { areValidationErrors } from './utils'
7import { isValidRSSFeed } from '../../helpers/custom-validators/feeds' 7import { isValidRSSFeed } from '../../helpers/custom-validators/feeds'
8import { doesVideoChannelIdExist, doesVideoChannelNameWithHostExist } from '../../helpers/custom-validators/video-channels' 8import { doesVideoChannelIdExist, doesVideoChannelNameWithHostExist } from '../../helpers/custom-validators/video-channels'
9import { doesVideoExist } from '../../helpers/custom-validators/videos' 9import { doesVideoExist } from '../../helpers/custom-validators/videos'
10import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor'
11 10
12const videoFeedsValidator = [ 11const videoFeedsValidator = [
13 param('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'), 12 param('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'),
14 query('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'), 13 query('format').optional().custom(isValidRSSFeed).withMessage('Should have a valid format (rss, atom, json)'),
15 query('accountId').optional().custom(isIdOrUUIDValid), 14 query('accountId').optional().custom(isIdValid),
16 query('accountName').optional().custom(isAccountNameValid), 15 query('accountName').optional(),
17 query('videoChannelId').optional().custom(isIdOrUUIDValid), 16 query('videoChannelId').optional().custom(isIdValid),
18 query('videoChannelName').optional().custom(isActorPreferredUsernameValid), 17 query('videoChannelName').optional(),
19 18
20 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 19 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
21 logger.debug('Checking feeds parameters', { parameters: req.query }) 20 logger.debug('Checking feeds parameters', { parameters: req.query })
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts
index 6d8cd7894..7a081af33 100644
--- a/server/middlewares/validators/users.ts
+++ b/server/middlewares/validators/users.ts
@@ -25,6 +25,10 @@ import { Redis } from '../../lib/redis'
25import { UserModel } from '../../models/account/user' 25import { UserModel } from '../../models/account/user'
26import { areValidationErrors } from './utils' 26import { areValidationErrors } from './utils'
27import { ActorModel } from '../../models/activitypub/actor' 27import { ActorModel } from '../../models/activitypub/actor'
28import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor'
29import { isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels'
30import { UserCreate } from '../../../shared/models/users'
31import { UserRegister } from '../../../shared/models/users/user-register.model'
28 32
29const usersAddValidator = [ 33const usersAddValidator = [
30 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), 34 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'),
@@ -49,6 +53,8 @@ const usersRegisterValidator = [
49 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username'), 53 body('username').custom(isUserUsernameValid).withMessage('Should have a valid username'),
50 body('password').custom(isUserPasswordValid).withMessage('Should have a valid password'), 54 body('password').custom(isUserPasswordValid).withMessage('Should have a valid password'),
51 body('email').isEmail().withMessage('Should have a valid email'), 55 body('email').isEmail().withMessage('Should have a valid email'),
56 body('channel.name').optional().custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'),
57 body('channel.displayName').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid display name'),
52 58
53 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 59 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
54 logger.debug('Checking usersRegister parameters', { parameters: omit(req.body, 'password') }) 60 logger.debug('Checking usersRegister parameters', { parameters: omit(req.body, 'password') })
@@ -56,6 +62,28 @@ const usersRegisterValidator = [
56 if (areValidationErrors(req, res)) return 62 if (areValidationErrors(req, res)) return
57 if (!await checkUserNameOrEmailDoesNotAlreadyExist(req.body.username, req.body.email, res)) return 63 if (!await checkUserNameOrEmailDoesNotAlreadyExist(req.body.username, req.body.email, res)) return
58 64
65 const body: UserRegister = req.body
66 if (body.channel) {
67 if (!body.channel.name || !body.channel.displayName) {
68 return res.status(400)
69 .send({ error: 'Channel is optional but if you specify it, channel.name and channel.displayName are required.' })
70 .end()
71 }
72
73 if (body.channel.name === body.username) {
74 return res.status(400)
75 .send({ error: 'Channel name cannot be the same than user username.' })
76 .end()
77 }
78
79 const existing = await ActorModel.loadLocalByName(body.channel.name)
80 if (existing) {
81 return res.status(409)
82 .send({ error: `Channel with name ${body.channel.name} already exists.` })
83 .end()
84 }
85 }
86
59 return next() 87 return next()
60 } 88 }
61] 89]
diff --git a/server/middlewares/validators/videos/video-channels.ts b/server/middlewares/validators/videos/video-channels.ts
index 4b26f0bc4..f5a59cacb 100644
--- a/server/middlewares/validators/videos/video-channels.ts
+++ b/server/middlewares/validators/videos/video-channels.ts
@@ -14,6 +14,7 @@ import { VideoChannelModel } from '../../../models/video/video-channel'
14import { areValidationErrors } from '../utils' 14import { areValidationErrors } from '../utils'
15import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor' 15import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor'
16import { ActorModel } from '../../../models/activitypub/actor' 16import { ActorModel } from '../../../models/activitypub/actor'
17import { isBooleanValid } from '../../../helpers/custom-validators/misc'
17 18
18const videoChannelsAddValidator = [ 19const videoChannelsAddValidator = [
19 body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'), 20 body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'),
@@ -40,9 +41,18 @@ const videoChannelsAddValidator = [
40 41
41const videoChannelsUpdateValidator = [ 42const videoChannelsUpdateValidator = [
42 param('nameWithHost').exists().withMessage('Should have an video channel name with host'), 43 param('nameWithHost').exists().withMessage('Should have an video channel name with host'),
43 body('displayName').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid display name'), 44 body('displayName')
44 body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'), 45 .optional()
45 body('support').optional().custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'), 46 .custom(isVideoChannelNameValid).withMessage('Should have a valid display name'),
47 body('description')
48 .optional()
49 .custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'),
50 body('support')
51 .optional()
52 .custom(isVideoChannelSupportValid).withMessage('Should have a valid support text'),
53 body('bulkVideosSupportUpdate')
54 .optional()
55 .custom(isBooleanValid).withMessage('Should have a valid bulkVideosSupportUpdate boolean field'),
46 56
47 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 57 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
48 logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body }) 58 logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body })
diff --git a/server/middlewares/validators/videos/video-playlists.ts b/server/middlewares/validators/videos/video-playlists.ts
index f68eeeeb3..9c88dd291 100644
--- a/server/middlewares/validators/videos/video-playlists.ts
+++ b/server/middlewares/validators/videos/video-playlists.ts
@@ -24,6 +24,9 @@ import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/
24import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model' 24import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
25 25
26const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([ 26const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
27 body('displayName')
28 .custom(isVideoPlaylistNameValid).withMessage('Should have a valid display name'),
29
27 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 30 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
28 logger.debug('Checking videoPlaylistsAddValidator parameters', { parameters: req.body }) 31 logger.debug('Checking videoPlaylistsAddValidator parameters', { parameters: req.body })
29 32
@@ -46,6 +49,10 @@ const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([
46 param('playlistId') 49 param('playlistId')
47 .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), 50 .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
48 51
52 body('displayName')
53 .optional()
54 .custom(isVideoPlaylistNameValid).withMessage('Should have a valid display name'),
55
49 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 56 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
50 logger.debug('Checking videoPlaylistsUpdateValidator parameters', { parameters: req.body }) 57 logger.debug('Checking videoPlaylistsUpdateValidator parameters', { parameters: req.body })
51 58
@@ -61,12 +68,6 @@ const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([
61 68
62 const body: VideoPlaylistUpdate = req.body 69 const body: VideoPlaylistUpdate = req.body
63 70
64 if (videoPlaylist.privacy !== VideoPlaylistPrivacy.PRIVATE && body.privacy === VideoPlaylistPrivacy.PRIVATE) {
65 cleanUpReqFiles(req)
66 return res.status(400)
67 .json({ error: 'Cannot set "private" a video playlist that was not private.' })
68 }
69
70 const newPrivacy = body.privacy || videoPlaylist.privacy 71 const newPrivacy = body.privacy || videoPlaylist.privacy
71 if (newPrivacy === VideoPlaylistPrivacy.PUBLIC && 72 if (newPrivacy === VideoPlaylistPrivacy.PUBLIC &&
72 ( 73 (
@@ -368,8 +369,6 @@ function getCommonPlaylistEditAttributes () {
368 + CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ') 369 + CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ')
369 ), 370 ),
370 371
371 body('displayName')
372 .custom(isVideoPlaylistNameValid).withMessage('Should have a valid display name'),
373 body('description') 372 body('description')
374 .optional() 373 .optional()
375 .customSanitizer(toValueOrNull) 374 .customSanitizer(toValueOrNull)
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts
index 2b01f108d..b1c05ab2d 100644
--- a/server/middlewares/validators/videos/videos.ts
+++ b/server/middlewares/validators/videos/videos.ts
@@ -111,18 +111,10 @@ const videosUpdateValidator = getCommonVideoEditAttributes().concat([
111 if (areErrorsInScheduleUpdate(req, res)) return cleanUpReqFiles(req) 111 if (areErrorsInScheduleUpdate(req, res)) return cleanUpReqFiles(req)
112 if (!await doesVideoExist(req.params.id, res)) return cleanUpReqFiles(req) 112 if (!await doesVideoExist(req.params.id, res)) return cleanUpReqFiles(req)
113 113
114 const video = res.locals.video
115
116 // Check if the user who did the request is able to update the video 114 // Check if the user who did the request is able to update the video
117 const user = res.locals.oauth.token.User 115 const user = res.locals.oauth.token.User
118 if (!checkUserCanManageVideo(user, res.locals.video, UserRight.UPDATE_ANY_VIDEO, res)) return cleanUpReqFiles(req) 116 if (!checkUserCanManageVideo(user, res.locals.video, UserRight.UPDATE_ANY_VIDEO, res)) return cleanUpReqFiles(req)
119 117
120 if (video.privacy !== VideoPrivacy.PRIVATE && req.body.privacy === VideoPrivacy.PRIVATE) {
121 cleanUpReqFiles(req)
122 return res.status(409)
123 .json({ error: 'Cannot set "private" a video that was not private.' })
124 }
125
126 if (req.body.channelId && !await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) 118 if (req.body.channelId && !await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req)
127 119
128 return next() 120 return next()
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index 2b04acd86..09cada096 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -47,7 +47,7 @@ export enum ScopeNames {
47 attributes: [ 'id', 'name' ], 47 attributes: [ 'id', 'name' ],
48 include: [ 48 include: [
49 { 49 {
50 attributes: [ 'id', 'uuid', 'preferredUsername', 'url', 'serverId', 'avatarId' ], 50 attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
51 model: ActorModel.unscoped(), 51 model: ActorModel.unscoped(),
52 required: true, 52 required: true,
53 where: whereActor, 53 where: whereActor,
@@ -180,22 +180,6 @@ export class AccountModel extends Model<AccountModel> {
180 return AccountModel.findByPk(id, { transaction }) 180 return AccountModel.findByPk(id, { transaction })
181 } 181 }
182 182
183 static loadByUUID (uuid: string) {
184 const query = {
185 include: [
186 {
187 model: ActorModel,
188 required: true,
189 where: {
190 uuid
191 }
192 }
193 ]
194 }
195
196 return AccountModel.findOne(query)
197 }
198
199 static loadByNameWithHost (nameWithHost: string) { 183 static loadByNameWithHost (nameWithHost: string) {
200 const [ accountName, host ] = nameWithHost.split('@') 184 const [ accountName, host ] = nameWithHost.split('@')
201 185
@@ -332,7 +316,6 @@ export class AccountModel extends Model<AccountModel> {
332 316
333 return { 317 return {
334 id: this.id, 318 id: this.id,
335 uuid: actor.uuid,
336 name: actor.name, 319 name: actor.name,
337 displayName: this.getDisplayName(), 320 displayName: this.getDisplayName(),
338 url: actor.url, 321 url: actor.url,
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts
index 4a466441c..bd6a2c8fd 100644
--- a/server/models/activitypub/actor.ts
+++ b/server/models/activitypub/actor.ts
@@ -7,13 +7,11 @@ import {
7 Column, 7 Column,
8 CreatedAt, 8 CreatedAt,
9 DataType, 9 DataType,
10 Default,
11 DefaultScope, 10 DefaultScope,
12 ForeignKey, 11 ForeignKey,
13 HasMany, 12 HasMany,
14 HasOne, 13 HasOne,
15 Is, 14 Is,
16 IsUUID,
17 Model, 15 Model,
18 Scopes, 16 Scopes,
19 Table, 17 Table,
@@ -120,10 +118,6 @@ export const unusedActorAttributesForAPI = [
120 fields: [ 'avatarId' ] 118 fields: [ 'avatarId' ]
121 }, 119 },
122 { 120 {
123 fields: [ 'uuid' ],
124 unique: true
125 },
126 {
127 fields: [ 'followersUrl' ] 121 fields: [ 'followersUrl' ]
128 } 122 }
129 ] 123 ]
@@ -135,12 +129,6 @@ export class ActorModel extends Model<ActorModel> {
135 type: ActivityPubActorType 129 type: ActivityPubActorType
136 130
137 @AllowNull(false) 131 @AllowNull(false)
138 @Default(DataType.UUIDV4)
139 @IsUUID(4)
140 @Column(DataType.UUID)
141 uuid: string
142
143 @AllowNull(false)
144 @Is('ActorPreferredUsername', value => throwIfNotValid(value, isActorPreferredUsernameValid, 'actor preferred username')) 132 @Is('ActorPreferredUsername', value => throwIfNotValid(value, isActorPreferredUsernameValid, 'actor preferred username'))
145 @Column 133 @Column
146 preferredUsername: string 134 preferredUsername: string
@@ -408,7 +396,6 @@ export class ActorModel extends Model<ActorModel> {
408 return { 396 return {
409 id: this.id, 397 id: this.id,
410 url: this.url, 398 url: this.url,
411 uuid: this.uuid,
412 name: this.preferredUsername, 399 name: this.preferredUsername,
413 host: this.getHost(), 400 host: this.getHost(),
414 hostRedundancyAllowed: this.getRedundancyAllowed(), 401 hostRedundancyAllowed: this.getRedundancyAllowed(),
@@ -454,7 +441,6 @@ export class ActorModel extends Model<ActorModel> {
454 endpoints: { 441 endpoints: {
455 sharedInbox: this.sharedInboxUrl 442 sharedInbox: this.sharedInboxUrl
456 }, 443 },
457 uuid: this.uuid,
458 publicKey: { 444 publicKey: {
459 id: this.getPublicKeyUrl(), 445 id: this.getPublicKeyUrl(),
460 owner: this.url, 446 owner: this.url,
diff --git a/server/models/video/thumbnail.ts b/server/models/video/thumbnail.ts
index 206e9a3d6..8faf0adba 100644
--- a/server/models/video/thumbnail.ts
+++ b/server/models/video/thumbnail.ts
@@ -107,10 +107,12 @@ export class ThumbnailModel extends Model<ThumbnailModel> {
107 return WEBSERVER.URL + staticPath + this.filename 107 return WEBSERVER.URL + staticPath + this.filename
108 } 108 }
109 109
110 removeThumbnail () { 110 getPath () {
111 const directory = ThumbnailModel.types[this.type].directory 111 const directory = ThumbnailModel.types[this.type].directory
112 const thumbnailPath = join(directory, this.filename) 112 return join(directory, this.filename)
113 }
113 114
114 return remove(thumbnailPath) 115 removeThumbnail () {
116 return remove(this.getPath())
115 } 117 }
116} 118}
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts
index fb70e6625..b0b261c88 100644
--- a/server/models/video/video-channel.ts
+++ b/server/models/video/video-channel.ts
@@ -72,7 +72,7 @@ type AvailableForListOptions = {
72 attributes: [ 'name', 'description', 'id', 'actorId' ], 72 attributes: [ 'name', 'description', 'id', 'actorId' ],
73 include: [ 73 include: [
74 { 74 {
75 attributes: [ 'uuid', 'preferredUsername', 'url', 'serverId', 'avatarId' ], 75 attributes: [ 'preferredUsername', 'url', 'serverId', 'avatarId' ],
76 model: ActorModel.unscoped(), 76 model: ActorModel.unscoped(),
77 required: true, 77 required: true,
78 include: [ 78 include: [
@@ -334,14 +334,21 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
334 }) 334 })
335 } 335 }
336 336
337 static listByAccount (accountId: number) { 337 static listByAccount (options: {
338 accountId: number,
339 start: number,
340 count: number,
341 sort: string
342 }) {
338 const query = { 343 const query = {
339 order: getSort('createdAt'), 344 offset: options.start,
345 limit: options.count,
346 order: getSort(options.sort),
340 include: [ 347 include: [
341 { 348 {
342 model: AccountModel, 349 model: AccountModel,
343 where: { 350 where: {
344 id: accountId 351 id: options.accountId
345 }, 352 },
346 required: true 353 required: true
347 } 354 }
@@ -380,24 +387,6 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
380 .findByPk(id) 387 .findByPk(id)
381 } 388 }
382 389
383 static loadByUUIDAndPopulateAccount (uuid: string) {
384 const query = {
385 include: [
386 {
387 model: ActorModel,
388 required: true,
389 where: {
390 uuid
391 }
392 }
393 ]
394 }
395
396 return VideoChannelModel
397 .scope([ ScopeNames.WITH_ACCOUNT ])
398 .findOne(query)
399 }
400
401 static loadByUrlAndPopulateAccount (url: string) { 390 static loadByUrlAndPopulateAccount (url: string) {
402 const query = { 391 const query = {
403 include: [ 392 include: [
@@ -503,7 +492,6 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
503 492
504 return { 493 return {
505 id: this.id, 494 id: this.id,
506 uuid: actor.uuid,
507 name: actor.name, 495 name: actor.name,
508 displayName: this.getDisplayName(), 496 displayName: this.getDisplayName(),
509 url: actor.url, 497 url: actor.url,
diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts
index 2203a7aba..05c490759 100644
--- a/server/models/video/video-file.ts
+++ b/server/models/video/video-file.ts
@@ -24,6 +24,7 @@ import { VideoModel } from './video'
24import { VideoRedundancyModel } from '../redundancy/video-redundancy' 24import { VideoRedundancyModel } from '../redundancy/video-redundancy'
25import { VideoStreamingPlaylistModel } from './video-streaming-playlist' 25import { VideoStreamingPlaylistModel } from './video-streaming-playlist'
26import { FindOptions, QueryTypes, Transaction } from 'sequelize' 26import { FindOptions, QueryTypes, Transaction } from 'sequelize'
27import { MIMETYPES } from '../../initializers/constants'
27 28
28@Table({ 29@Table({
29 tableName: 'videoFile', 30 tableName: 'videoFile',
@@ -161,6 +162,10 @@ export class VideoFileModel extends Model<VideoFileModel> {
161 })) 162 }))
162 } 163 }
163 164
165 isAudio () {
166 return !!MIMETYPES.AUDIO.EXT_MIMETYPE[this.extname]
167 }
168
164 hasSameUniqueKeysThan (other: VideoFileModel) { 169 hasSameUniqueKeysThan (other: VideoFileModel) {
165 return this.fps === other.fps && 170 return this.fps === other.fps &&
166 this.resolution === other.resolution && 171 this.resolution === other.resolution &&
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index c0a7892a4..eccf0a4fa 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -1515,6 +1515,29 @@ export class VideoModel extends Model<VideoModel> {
1515 .then(results => results.length === 1) 1515 .then(results => results.length === 1)
1516 } 1516 }
1517 1517
1518 static bulkUpdateSupportField (videoChannel: VideoChannelModel, t: Transaction) {
1519 const options = {
1520 where: {
1521 channelId: videoChannel.id
1522 },
1523 transaction: t
1524 }
1525
1526 return VideoModel.update({ support: videoChannel.support }, options)
1527 }
1528
1529 static getAllIdsFromChannel (videoChannel: VideoChannelModel) {
1530 const query = {
1531 attributes: [ 'id' ],
1532 where: {
1533 channelId: videoChannel.id
1534 }
1535 }
1536
1537 return VideoModel.findAll(query)
1538 .then(videos => videos.map(v => v.id))
1539 }
1540
1518 // threshold corresponds to how many video the field should have to be returned 1541 // threshold corresponds to how many video the field should have to be returned
1519 static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) { 1542 static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) {
1520 const serverActor = await getServerActor() 1543 const serverActor = await getServerActor()
diff --git a/server/tests/api/activitypub/client.ts b/server/tests/api/activitypub/client.ts
index edf588c16..34c6be49b 100644
--- a/server/tests/api/activitypub/client.ts
+++ b/server/tests/api/activitypub/client.ts
@@ -3,6 +3,7 @@
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import {
6 cleanupTests,
6 doubleFollow, 7 doubleFollow,
7 flushAndRunMultipleServers, 8 flushAndRunMultipleServers,
8 flushTests, 9 flushTests,
@@ -39,7 +40,7 @@ describe('Test activitypub', function () {
39 const object = res.body 40 const object = res.body
40 41
41 expect(object.type).to.equal('Person') 42 expect(object.type).to.equal('Person')
42 expect(object.id).to.equal('http://localhost:9001/accounts/root') 43 expect(object.id).to.equal('http://localhost:' + servers[0].port + '/accounts/root')
43 expect(object.name).to.equal('root') 44 expect(object.name).to.equal('root')
44 expect(object.preferredUsername).to.equal('root') 45 expect(object.preferredUsername).to.equal('root')
45 }) 46 })
@@ -49,17 +50,17 @@ describe('Test activitypub', function () {
49 const object = res.body 50 const object = res.body
50 51
51 expect(object.type).to.equal('Video') 52 expect(object.type).to.equal('Video')
52 expect(object.id).to.equal('http://localhost:9001/videos/watch/' + videoUUID) 53 expect(object.id).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + videoUUID)
53 expect(object.name).to.equal('video') 54 expect(object.name).to.equal('video')
54 }) 55 })
55 56
56 it('Should redirect to the origin video object', async function () { 57 it('Should redirect to the origin video object', async function () {
57 const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + videoUUID, 302) 58 const res = await makeActivityPubGetRequest(servers[1].url, '/videos/watch/' + videoUUID, 302)
58 59
59 expect(res.header.location).to.equal('http://localhost:9001/videos/watch/' + videoUUID) 60 expect(res.header.location).to.equal('http://localhost:' + servers[0].port + '/videos/watch/' + videoUUID)
60 }) 61 })
61 62
62 after(function () { 63 after(async function () {
63 killallServers(servers) 64 await cleanupTests(servers)
64 }) 65 })
65}) 66})
diff --git a/server/tests/api/activitypub/fetch.ts b/server/tests/api/activitypub/fetch.ts
index 7240bb0fb..3a1c0d321 100644
--- a/server/tests/api/activitypub/fetch.ts
+++ b/server/tests/api/activitypub/fetch.ts
@@ -3,6 +3,7 @@
3import 'mocha' 3import 'mocha'
4 4
5import { 5import {
6 cleanupTests,
6 closeAllSequelize, 7 closeAllSequelize,
7 createUser, 8 createUser,
8 doubleFollow, 9 doubleFollow,
@@ -48,8 +49,16 @@ describe('Test ActivityPub fetcher', function () {
48 const badVideoUUID = res.body.video.uuid 49 const badVideoUUID = res.body.video.uuid
49 await uploadVideo(servers[0].url, userAccessToken, { name: 'video user' }) 50 await uploadVideo(servers[0].url, userAccessToken, { name: 'video user' })
50 51
51 await setActorField(1, 'http://localhost:9001/accounts/user1', 'url', 'http://localhost:9002/accounts/user1') 52 {
52 await setVideoField(1, badVideoUUID, 'url', 'http://localhost:9003/videos/watch/' + badVideoUUID) 53 const to = 'http://localhost:' + servers[0].port + '/accounts/user1'
54 const value = 'http://localhost:' + servers[1].port + '/accounts/user1'
55 await setActorField(servers[0].internalServerNumber, to, 'url', value)
56 }
57
58 {
59 const value = 'http://localhost:' + servers[2].port + '/videos/watch/' + badVideoUUID
60 await setVideoField(servers[0].internalServerNumber, badVideoUUID, 'url', value)
61 }
53 }) 62 })
54 63
55 it('Should add only the video with a valid actor URL', async function () { 64 it('Should add only the video with a valid actor URL', async function () {
@@ -78,7 +87,9 @@ describe('Test ActivityPub fetcher', function () {
78 }) 87 })
79 88
80 after(async function () { 89 after(async function () {
81 killallServers(servers) 90 this.timeout(10000)
91
92 await cleanupTests(servers)
82 93
83 await closeAllSequelize(servers) 94 await closeAllSequelize(servers)
84 }) 95 })
diff --git a/server/tests/api/activitypub/refresher.ts b/server/tests/api/activitypub/refresher.ts
index 9be9aa495..921ee874c 100644
--- a/server/tests/api/activitypub/refresher.ts
+++ b/server/tests/api/activitypub/refresher.ts
@@ -2,13 +2,14 @@
2 2
3import 'mocha' 3import 'mocha'
4import { 4import {
5 cleanupTests, closeAllSequelize,
5 createVideoPlaylist, 6 createVideoPlaylist,
6 doubleFollow, 7 doubleFollow,
7 flushAndRunMultipleServers, 8 flushAndRunMultipleServers,
8 generateUserAccessToken, 9 generateUserAccessToken,
9 getVideo, 10 getVideo,
10 getVideoPlaylist, 11 getVideoPlaylist,
11 killallServers, rateVideo, 12 killallServers,
12 reRunServer, 13 reRunServer,
13 ServerInfo, 14 ServerInfo,
14 setAccessTokensToServers, 15 setAccessTokensToServers,
@@ -48,26 +49,26 @@ describe('Test AP refresher', function () {
48 } 49 }
49 50
50 { 51 {
51 const a1 = await generateUserAccessToken(servers[1], 'user1') 52 const a1 = await generateUserAccessToken(servers[ 1 ], 'user1')
52 await uploadVideo(servers[1].url, a1, { name: 'video4' }) 53 await uploadVideo(servers[ 1 ].url, a1, { name: 'video4' })
53 54
54 const a2 = await generateUserAccessToken(servers[1], 'user2') 55 const a2 = await generateUserAccessToken(servers[ 1 ], 'user2')
55 await uploadVideo(servers[1].url, a2, { name: 'video5' }) 56 await uploadVideo(servers[ 1 ].url, a2, { name: 'video5' })
56 } 57 }
57 58
58 { 59 {
59 const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id } 60 const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id }
60 const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs }) 61 const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs })
61 playlistUUID1 = res.body.videoPlaylist.uuid 62 playlistUUID1 = res.body.videoPlaylist.uuid
62 } 63 }
63 64
64 { 65 {
65 const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id } 66 const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id }
66 const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs }) 67 const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs })
67 playlistUUID2 = res.body.videoPlaylist.uuid 68 playlistUUID2 = res.body.videoPlaylist.uuid
68 } 69 }
69 70
70 await doubleFollow(servers[0], servers[1]) 71 await doubleFollow(servers[ 0 ], servers[ 1 ])
71 }) 72 })
72 73
73 describe('Videos refresher', function () { 74 describe('Videos refresher', function () {
@@ -78,7 +79,7 @@ describe('Test AP refresher', function () {
78 await wait(10000) 79 await wait(10000)
79 80
80 // Change UUID so the remote server returns a 404 81 // Change UUID so the remote server returns a 404
81 await setVideoField(2, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f') 82 await setVideoField(servers[ 1 ].internalServerNumber, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f')
82 83
83 await getVideo(servers[ 0 ].url, videoUUID1) 84 await getVideo(servers[ 0 ].url, videoUUID1)
84 await getVideo(servers[ 0 ].url, videoUUID2) 85 await getVideo(servers[ 0 ].url, videoUUID2)
@@ -94,7 +95,7 @@ describe('Test AP refresher', function () {
94 95
95 killallServers([ servers[ 1 ] ]) 96 killallServers([ servers[ 1 ] ])
96 97
97 await setVideoField(2, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e') 98 await setVideoField(servers[ 1 ].internalServerNumber, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e')
98 99
99 // Video will need a refresh 100 // Video will need a refresh
100 await wait(10000) 101 await wait(10000)
@@ -121,15 +122,16 @@ describe('Test AP refresher', function () {
121 await wait(10000) 122 await wait(10000)
122 123
123 // Change actor name so the remote server returns a 404 124 // Change actor name so the remote server returns a 404
124 await setActorField(2, 'http://localhost:9002/accounts/user2', 'preferredUsername', 'toto') 125 const to = 'http://localhost:' + servers[ 1 ].port + '/accounts/user2'
126 await setActorField(servers[ 1 ].internalServerNumber, to, 'preferredUsername', 'toto')
125 127
126 await getAccount(servers[ 0 ].url, 'user1@localhost:9002') 128 await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port)
127 await getAccount(servers[ 0 ].url, 'user2@localhost:9002') 129 await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port)
128 130
129 await waitJobs(servers) 131 await waitJobs(servers)
130 132
131 await getAccount(servers[ 0 ].url, 'user1@localhost:9002', 200) 133 await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port, 200)
132 await getAccount(servers[ 0 ].url, 'user2@localhost:9002', 404) 134 await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port, 404)
133 }) 135 })
134 }) 136 })
135 137
@@ -141,7 +143,7 @@ describe('Test AP refresher', function () {
141 await wait(10000) 143 await wait(10000)
142 144
143 // Change UUID so the remote server returns a 404 145 // Change UUID so the remote server returns a 404
144 await setPlaylistField(2, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e') 146 await setPlaylistField(servers[ 1 ].internalServerNumber, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e')
145 147
146 await getVideoPlaylist(servers[ 0 ].url, playlistUUID1) 148 await getVideoPlaylist(servers[ 0 ].url, playlistUUID1)
147 await getVideoPlaylist(servers[ 0 ].url, playlistUUID2) 149 await getVideoPlaylist(servers[ 0 ].url, playlistUUID2)
@@ -153,7 +155,11 @@ describe('Test AP refresher', function () {
153 }) 155 })
154 }) 156 })
155 157
156 after(function () { 158 after(async function () {
157 killallServers(servers) 159 this.timeout(10000)
160
161 await cleanupTests(servers)
162
163 await closeAllSequelize(servers)
158 }) 164 })
159}) 165})
diff --git a/server/tests/api/activitypub/security.ts b/server/tests/api/activitypub/security.ts
index 11e6859bf..dc960c5c3 100644
--- a/server/tests/api/activitypub/security.ts
+++ b/server/tests/api/activitypub/security.ts
@@ -3,9 +3,9 @@
3import 'mocha' 3import 'mocha'
4 4
5import { 5import {
6 cleanupTests,
6 closeAllSequelize, 7 closeAllSequelize,
7 flushAndRunMultipleServers, 8 flushAndRunMultipleServers,
8 flushTests,
9 killallServers, 9 killallServers,
10 ServerInfo, 10 ServerInfo,
11 setActorField 11 setActorField
@@ -18,18 +18,26 @@ import { makeFollowRequest, makePOSTAPRequest } from '../../../../shared/extra-u
18 18
19const expect = chai.expect 19const expect = chai.expect
20 20
21function setKeysOfServer2 (serverNumber: number, publicKey: string, privateKey: string) { 21function setKeysOfServer (onServer: ServerInfo, ofServer: ServerInfo, publicKey: string, privateKey: string) {
22 return Promise.all([ 22 return Promise.all([
23 setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'publicKey', publicKey), 23 setActorField(onServer.internalServerNumber, 'http://localhost:' + ofServer.port + '/accounts/peertube', 'publicKey', publicKey),
24 setActorField(serverNumber, 'http://localhost:9002/accounts/peertube', 'privateKey', privateKey) 24 setActorField(onServer.internalServerNumber, 'http://localhost:' + ofServer.port + '/accounts/peertube', 'privateKey', privateKey)
25 ]) 25 ])
26} 26}
27 27
28function setKeysOfServer3 (serverNumber: number, publicKey: string, privateKey: string) { 28function getAnnounceWithoutContext (server2: ServerInfo) {
29 return Promise.all([ 29 const json = require('./json/peertube/announce-without-context.json')
30 setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'publicKey', publicKey), 30 const result: typeof json = {}
31 setActorField(serverNumber, 'http://localhost:9003/accounts/peertube', 'privateKey', privateKey) 31
32 ]) 32 for (const key of Object.keys(json)) {
33 if (Array.isArray(json[key])) {
34 result[key] = json[key].map(v => v.replace(':9002', `:${server2.port}`))
35 } else {
36 result[ key ] = json[ key ].replace(':9002', `:${server2.port}`)
37 }
38 }
39
40 return result
33} 41}
34 42
35describe('Test ActivityPub security', function () { 43describe('Test ActivityPub security', function () {
@@ -38,13 +46,13 @@ describe('Test ActivityPub security', function () {
38 46
39 const keys = require('./json/peertube/keys.json') 47 const keys = require('./json/peertube/keys.json')
40 const invalidKeys = require('./json/peertube/invalid-keys.json') 48 const invalidKeys = require('./json/peertube/invalid-keys.json')
41 const baseHttpSignature = { 49 const baseHttpSignature = () => ({
42 algorithm: HTTP_SIGNATURE.ALGORITHM, 50 algorithm: HTTP_SIGNATURE.ALGORITHM,
43 authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, 51 authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME,
44 keyId: 'acct:peertube@localhost:9002', 52 keyId: 'acct:peertube@localhost:' + servers[1].port,
45 key: keys.privateKey, 53 key: keys.privateKey,
46 headers: HTTP_SIGNATURE.HEADERS_TO_SIGN 54 headers: HTTP_SIGNATURE.HEADERS_TO_SIGN
47 } 55 })
48 56
49 // --------------------------------------------------------------- 57 // ---------------------------------------------------------------
50 58
@@ -55,56 +63,56 @@ describe('Test ActivityPub security', function () {
55 63
56 url = servers[0].url + '/inbox' 64 url = servers[0].url + '/inbox'
57 65
58 await setKeysOfServer2(1, keys.publicKey, keys.privateKey) 66 await setKeysOfServer(servers[0], servers[1], keys.publicKey, keys.privateKey)
59 67
60 const to = { url: 'http://localhost:9001/accounts/peertube' } 68 const to = { url: 'http://localhost:' + servers[0].port + '/accounts/peertube' }
61 const by = { url: 'http://localhost:9002/accounts/peertube', privateKey: keys.privateKey } 69 const by = { url: 'http://localhost:' + servers[1].port + '/accounts/peertube', privateKey: keys.privateKey }
62 await makeFollowRequest(to, by) 70 await makeFollowRequest(to, by)
63 }) 71 })
64 72
65 describe('When checking HTTP signature', function () { 73 describe('When checking HTTP signature', function () {
66 74
67 it('Should fail with an invalid digest', async function () { 75 it('Should fail with an invalid digest', async function () {
68 const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) 76 const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
69 const headers = { 77 const headers = {
70 Digest: buildDigest({ hello: 'coucou' }) 78 Digest: buildDigest({ hello: 'coucou' })
71 } 79 }
72 80
73 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) 81 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
74 82
75 expect(response.statusCode).to.equal(403) 83 expect(response.statusCode).to.equal(403)
76 }) 84 })
77 85
78 it('Should fail with an invalid date', async function () { 86 it('Should fail with an invalid date', async function () {
79 const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) 87 const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
80 const headers = buildGlobalHeaders(body) 88 const headers = buildGlobalHeaders(body)
81 headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT' 89 headers['date'] = 'Wed, 21 Oct 2015 07:28:00 GMT'
82 90
83 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) 91 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
84 92
85 expect(response.statusCode).to.equal(403) 93 expect(response.statusCode).to.equal(403)
86 }) 94 })
87 95
88 it('Should fail with bad keys', async function () { 96 it('Should fail with bad keys', async function () {
89 await setKeysOfServer2(1, invalidKeys.publicKey, invalidKeys.privateKey) 97 await setKeysOfServer(servers[0], servers[1], invalidKeys.publicKey, invalidKeys.privateKey)
90 await setKeysOfServer2(2, invalidKeys.publicKey, invalidKeys.privateKey) 98 await setKeysOfServer(servers[1], servers[1], invalidKeys.publicKey, invalidKeys.privateKey)
91 99
92 const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) 100 const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
93 const headers = buildGlobalHeaders(body) 101 const headers = buildGlobalHeaders(body)
94 102
95 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) 103 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
96 104
97 expect(response.statusCode).to.equal(403) 105 expect(response.statusCode).to.equal(403)
98 }) 106 })
99 107
100 it('Should succeed with a valid HTTP signature', async function () { 108 it('Should succeed with a valid HTTP signature', async function () {
101 await setKeysOfServer2(1, keys.publicKey, keys.privateKey) 109 await setKeysOfServer(servers[0], servers[1], keys.publicKey, keys.privateKey)
102 await setKeysOfServer2(2, keys.publicKey, keys.privateKey) 110 await setKeysOfServer(servers[1], servers[1], keys.publicKey, keys.privateKey)
103 111
104 const body = activityPubContextify(require('./json/peertube/announce-without-context.json')) 112 const body = activityPubContextify(getAnnounceWithoutContext(servers[1]))
105 const headers = buildGlobalHeaders(body) 113 const headers = buildGlobalHeaders(body)
106 114
107 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature, headers) 115 const { response } = await makePOSTAPRequest(url, body, baseHttpSignature(), headers)
108 116
109 expect(response.statusCode).to.equal(204) 117 expect(response.statusCode).to.equal(204)
110 }) 118 })
@@ -112,28 +120,28 @@ describe('Test ActivityPub security', function () {
112 120
113 describe('When checking Linked Data Signature', function () { 121 describe('When checking Linked Data Signature', function () {
114 before(async () => { 122 before(async () => {
115 await setKeysOfServer3(3, keys.publicKey, keys.privateKey) 123 await setKeysOfServer(servers[2], servers[2], keys.publicKey, keys.privateKey)
116 124
117 const to = { url: 'http://localhost:9001/accounts/peertube' } 125 const to = { url: 'http://localhost:' + servers[0].port + '/accounts/peertube' }
118 const by = { url: 'http://localhost:9003/accounts/peertube', privateKey: keys.privateKey } 126 const by = { url: 'http://localhost:' + servers[2].port + '/accounts/peertube', privateKey: keys.privateKey }
119 await makeFollowRequest(to, by) 127 await makeFollowRequest(to, by)
120 }) 128 })
121 129
122 it('Should fail with bad keys', async function () { 130 it('Should fail with bad keys', async function () {
123 this.timeout(10000) 131 this.timeout(10000)
124 132
125 await setKeysOfServer3(1, invalidKeys.publicKey, invalidKeys.privateKey) 133 await setKeysOfServer(servers[0], servers[2], invalidKeys.publicKey, invalidKeys.privateKey)
126 await setKeysOfServer3(3, invalidKeys.publicKey, invalidKeys.privateKey) 134 await setKeysOfServer(servers[2], servers[2], invalidKeys.publicKey, invalidKeys.privateKey)
127 135
128 const body = require('./json/peertube/announce-without-context.json') 136 const body = getAnnounceWithoutContext(servers[1])
129 body.actor = 'http://localhost:9003/accounts/peertube' 137 body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
130 138
131 const signer: any = { privateKey: invalidKeys.privateKey, url: 'http://localhost:9003/accounts/peertube' } 139 const signer: any = { privateKey: invalidKeys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
132 const signedBody = await buildSignedActivity(signer, body) 140 const signedBody = await buildSignedActivity(signer, body)
133 141
134 const headers = buildGlobalHeaders(signedBody) 142 const headers = buildGlobalHeaders(signedBody)
135 143
136 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers) 144 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers)
137 145
138 expect(response.statusCode).to.equal(403) 146 expect(response.statusCode).to.equal(403)
139 }) 147 })
@@ -141,20 +149,20 @@ describe('Test ActivityPub security', function () {
141 it('Should fail with an altered body', async function () { 149 it('Should fail with an altered body', async function () {
142 this.timeout(10000) 150 this.timeout(10000)
143 151
144 await setKeysOfServer3(1, keys.publicKey, keys.privateKey) 152 await setKeysOfServer(servers[0], servers[2], keys.publicKey, keys.privateKey)
145 await setKeysOfServer3(3, keys.publicKey, keys.privateKey) 153 await setKeysOfServer(servers[0], servers[2], keys.publicKey, keys.privateKey)
146 154
147 const body = require('./json/peertube/announce-without-context.json') 155 const body = getAnnounceWithoutContext(servers[1])
148 body.actor = 'http://localhost:9003/accounts/peertube' 156 body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
149 157
150 const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' } 158 const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
151 const signedBody = await buildSignedActivity(signer, body) 159 const signedBody = await buildSignedActivity(signer, body)
152 160
153 signedBody.actor = 'http://localhost:9003/account/peertube' 161 signedBody.actor = 'http://localhost:' + servers[2].port + '/account/peertube'
154 162
155 const headers = buildGlobalHeaders(signedBody) 163 const headers = buildGlobalHeaders(signedBody)
156 164
157 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers) 165 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers)
158 166
159 expect(response.statusCode).to.equal(403) 167 expect(response.statusCode).to.equal(403)
160 }) 168 })
@@ -162,22 +170,24 @@ describe('Test ActivityPub security', function () {
162 it('Should succeed with a valid signature', async function () { 170 it('Should succeed with a valid signature', async function () {
163 this.timeout(10000) 171 this.timeout(10000)
164 172
165 const body = require('./json/peertube/announce-without-context.json') 173 const body = getAnnounceWithoutContext(servers[1])
166 body.actor = 'http://localhost:9003/accounts/peertube' 174 body.actor = 'http://localhost:' + servers[2].port + '/accounts/peertube'
167 175
168 const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:9003/accounts/peertube' } 176 const signer: any = { privateKey: keys.privateKey, url: 'http://localhost:' + servers[2].port + '/accounts/peertube' }
169 const signedBody = await buildSignedActivity(signer, body) 177 const signedBody = await buildSignedActivity(signer, body)
170 178
171 const headers = buildGlobalHeaders(signedBody) 179 const headers = buildGlobalHeaders(signedBody)
172 180
173 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature, headers) 181 const { response } = await makePOSTAPRequest(url, signedBody, baseHttpSignature(), headers)
174 182
175 expect(response.statusCode).to.equal(204) 183 expect(response.statusCode).to.equal(204)
176 }) 184 })
177 }) 185 })
178 186
179 after(async function () { 187 after(async function () {
180 killallServers(servers) 188 this.timeout(10000)
189
190 await cleanupTests(servers)
181 191
182 await closeAllSequelize(servers) 192 await closeAllSequelize(servers)
183 }) 193 })
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts
index 2a2ec606a..8155e11ab 100644
--- a/server/tests/api/check-params/config.ts
+++ b/server/tests/api/check-params/config.ts
@@ -59,6 +59,7 @@ describe('Test config API validators', function () {
59 transcoding: { 59 transcoding: {
60 enabled: true, 60 enabled: true,
61 allowAdditionalExtensions: true, 61 allowAdditionalExtensions: true,
62 allowAudioFiles: true,
62 threads: 1, 63 threads: 1,
63 resolutions: { 64 resolutions: {
64 '240p': false, 65 '240p': false,
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts
index 5935104a5..95097817b 100644
--- a/server/tests/api/check-params/users.ts
+++ b/server/tests/api/check-params/users.ts
@@ -6,6 +6,7 @@ import { join } from 'path'
6import { UserRole, VideoImport, VideoImportState } from '../../../../shared' 6import { UserRole, VideoImport, VideoImportState } from '../../../../shared'
7 7
8import { 8import {
9 addVideoChannel,
9 blockUser, 10 blockUser,
10 cleanupTests, 11 cleanupTests,
11 createUser, 12 createUser,
@@ -638,7 +639,7 @@ describe('Test users API validators', function () {
638 }) 639 })
639 }) 640 })
640 641
641 describe('When register a new user', function () { 642 describe('When registering a new user', function () {
642 const registrationPath = path + '/register' 643 const registrationPath = path + '/register'
643 const baseCorrectParams = { 644 const baseCorrectParams = {
644 username: 'user3', 645 username: 'user3',
@@ -724,12 +725,42 @@ describe('Test users API validators', function () {
724 }) 725 })
725 }) 726 })
726 727
728 it('Should fail with a bad channel name', async function () {
729 const fields = immutableAssign(baseCorrectParams, { channel: { name: '[]azf', displayName: 'toto' } })
730
731 await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
732 })
733
734 it('Should fail with a bad channel display name', async function () {
735 const fields = immutableAssign(baseCorrectParams, { channel: { name: 'toto', displayName: '' } })
736
737 await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
738 })
739
740 it('Should fail with a channel name that is the same than user username', async function () {
741 const source = { username: 'super_user', channel: { name: 'super_user', displayName: 'display name' } }
742 const fields = immutableAssign(baseCorrectParams, source)
743
744 await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
745 })
746
747 it('Should fail with an existing channel', async function () {
748 const videoChannelAttributesArg = { name: 'existing_channel', displayName: 'hello', description: 'super description' }
749 await addVideoChannel(server.url, server.accessToken, videoChannelAttributesArg)
750
751 const fields = immutableAssign(baseCorrectParams, { channel: { name: 'existing_channel', displayName: 'toto' } })
752
753 await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields, statusCodeExpected: 409 })
754 })
755
727 it('Should succeed with the correct params', async function () { 756 it('Should succeed with the correct params', async function () {
757 const fields = immutableAssign(baseCorrectParams, { channel: { name: 'super_channel', displayName: 'toto' } })
758
728 await makePostBodyRequest({ 759 await makePostBodyRequest({
729 url: server.url, 760 url: server.url,
730 path: registrationPath, 761 path: registrationPath,
731 token: server.accessToken, 762 token: server.accessToken,
732 fields: baseCorrectParams, 763 fields: fields,
733 statusCodeExpected: 204 764 statusCodeExpected: 204
734 }) 765 })
735 }) 766 })
diff --git a/server/tests/api/check-params/video-channels.ts b/server/tests/api/check-params/video-channels.ts
index 65bc20613..de88298d1 100644
--- a/server/tests/api/check-params/video-channels.ts
+++ b/server/tests/api/check-params/video-channels.ts
@@ -24,6 +24,7 @@ import {
24 checkBadStartPagination 24 checkBadStartPagination
25} from '../../../../shared/extra-utils/requests/check-api-params' 25} from '../../../../shared/extra-utils/requests/check-api-params'
26import { join } from 'path' 26import { join } from 'path'
27import { VideoChannelUpdate } from '../../../../shared/models/videos'
27 28
28const expect = chai.expect 29const expect = chai.expect
29 30
@@ -67,8 +68,30 @@ describe('Test video channels API validator', function () {
67 }) 68 })
68 69
69 describe('When listing account video channels', function () { 70 describe('When listing account video channels', function () {
71 const accountChannelPath = '/api/v1/accounts/fake/video-channels'
72
73 it('Should fail with a bad start pagination', async function () {
74 await checkBadStartPagination(server.url, accountChannelPath, server.accessToken)
75 })
76
77 it('Should fail with a bad count pagination', async function () {
78 await checkBadCountPagination(server.url, accountChannelPath, server.accessToken)
79 })
80
81 it('Should fail with an incorrect sort', async function () {
82 await checkBadSortPagination(server.url, accountChannelPath, server.accessToken)
83 })
84
70 it('Should fail with a unknown account', async function () { 85 it('Should fail with a unknown account', async function () {
71 await getAccountVideoChannelsList(server.url, 'unknown', 404) 86 await getAccountVideoChannelsList({ url: server.url, accountName: 'unknown', specialStatus: 404 })
87 })
88
89 it('Should succeed with the correct parameters', async function () {
90 await makeGetRequest({
91 url: server.url,
92 path: accountChannelPath,
93 statusCodeExpected: 200
94 })
72 }) 95 })
73 }) 96 })
74 97
@@ -147,9 +170,11 @@ describe('Test video channels API validator', function () {
147 }) 170 })
148 171
149 describe('When updating a video channel', function () { 172 describe('When updating a video channel', function () {
150 const baseCorrectParams = { 173 const baseCorrectParams: VideoChannelUpdate = {
151 displayName: 'hello', 174 displayName: 'hello',
152 description: 'super description' 175 description: 'super description',
176 support: 'toto',
177 bulkVideosSupportUpdate: false
153 } 178 }
154 let path: string 179 let path: string
155 180
@@ -192,6 +217,11 @@ describe('Test video channels API validator', function () {
192 await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields }) 217 await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
193 }) 218 })
194 219
220 it('Should fail with a bad bulkVideosSupportUpdate field', async function () {
221 const fields = immutableAssign(baseCorrectParams, { bulkVideosSupportUpdate: 'super' })
222 await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
223 })
224
195 it('Should succeed with the correct parameters', async function () { 225 it('Should succeed with the correct parameters', async function () {
196 await makePutBodyRequest({ 226 await makePutBodyRequest({
197 url: server.url, 227 url: server.url,
diff --git a/server/tests/api/check-params/video-playlists.ts b/server/tests/api/check-params/video-playlists.ts
index b7b94c035..8c5e44bdd 100644
--- a/server/tests/api/check-params/video-playlists.ts
+++ b/server/tests/api/check-params/video-playlists.ts
@@ -205,7 +205,6 @@ describe('Test video playlists API validator', function () {
205 const params = getBase({ displayName: undefined }) 205 const params = getBase({ displayName: undefined })
206 206
207 await createVideoPlaylist(params) 207 await createVideoPlaylist(params)
208 await updateVideoPlaylist(getUpdate(params, playlistUUID))
209 }) 208 })
210 209
211 it('Should fail with an incorrect display name', async function () { 210 it('Should fail with an incorrect display name', async function () {
@@ -269,17 +268,6 @@ describe('Test video playlists API validator', function () {
269 )) 268 ))
270 }) 269 })
271 270
272 it('Should fail to update to private a public/unlisted playlist', async function () {
273 const params = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC }, { expectedStatus: 200 })
274
275 const res = await createVideoPlaylist(params)
276 const playlist = res.body.videoPlaylist
277
278 const paramsUpdate = getBase({ privacy: VideoPlaylistPrivacy.PRIVATE }, { expectedStatus: 400 })
279
280 await updateVideoPlaylist(getUpdate(paramsUpdate, playlist.id))
281 })
282
283 it('Should fail to update the watch later playlist', async function () { 271 it('Should fail to update the watch later playlist', async function () {
284 await updateVideoPlaylist(getUpdate( 272 await updateVideoPlaylist(getUpdate(
285 getBase({}, { expectedStatus: 400 }), 273 getBase({}, { expectedStatus: 400 }),
diff --git a/server/tests/api/index-1.ts b/server/tests/api/index-1.ts
deleted file mode 100644
index 75cdd9025..000000000
--- a/server/tests/api/index-1.ts
+++ /dev/null
@@ -1,3 +0,0 @@
1import './check-params'
2import './notifications'
3import './search'
diff --git a/server/tests/api/index-2.ts b/server/tests/api/index-2.ts
deleted file mode 100644
index ed93faa91..000000000
--- a/server/tests/api/index-2.ts
+++ /dev/null
@@ -1,2 +0,0 @@
1import './server'
2import './users'
diff --git a/server/tests/api/index-3.ts b/server/tests/api/index-3.ts
deleted file mode 100644
index 39823b82c..000000000
--- a/server/tests/api/index-3.ts
+++ /dev/null
@@ -1 +0,0 @@
1import './videos'
diff --git a/server/tests/api/index-4.ts b/server/tests/api/index-4.ts
deleted file mode 100644
index 7d8be2b3d..000000000
--- a/server/tests/api/index-4.ts
+++ /dev/null
@@ -1,2 +0,0 @@
1import './redundancy'
2import './activitypub'
diff --git a/server/tests/api/index.ts b/server/tests/api/index.ts
index bc140f860..bac77ab2e 100644
--- a/server/tests/api/index.ts
+++ b/server/tests/api/index.ts
@@ -1,5 +1,9 @@
1// Order of the tests we want to execute 1// Order of the tests we want to execute
2import './index-1' 2import './activitypub'
3import './index-2' 3import './check-params'
4import './index-3' 4import './notifications'
5import './index-4' 5import './redundancy'
6import './search'
7import './server'
8import './users'
9import './videos'
diff --git a/server/tests/api/notifications/index.ts b/server/tests/api/notifications/index.ts
index 95ac8fc51..b573f850e 100644
--- a/server/tests/api/notifications/index.ts
+++ b/server/tests/api/notifications/index.ts
@@ -1 +1 @@
export * from './user-notifications' import './user-notifications'
diff --git a/server/tests/api/notifications/user-notifications.ts b/server/tests/api/notifications/user-notifications.ts
index f479e1785..662b64e05 100644
--- a/server/tests/api/notifications/user-notifications.ts
+++ b/server/tests/api/notifications/user-notifications.ts
@@ -114,11 +114,12 @@ describe('Test users notifications', function () {
114 before(async function () { 114 before(async function () {
115 this.timeout(120000) 115 this.timeout(120000)
116 116
117 await MockSmtpServer.Instance.collectEmails(emails) 117 const port = await MockSmtpServer.Instance.collectEmails(emails)
118 118
119 const overrideConfig = { 119 const overrideConfig = {
120 smtp: { 120 smtp: {
121 hostname: 'localhost' 121 hostname: 'localhost',
122 port
122 } 123 }
123 } 124 }
124 servers = await flushAndRunMultipleServers(3, overrideConfig) 125 servers = await flushAndRunMultipleServers(3, overrideConfig)
@@ -194,7 +195,7 @@ describe('Test users notifications', function () {
194 it('Should send a new video notification if the user follows the local video publisher', async function () { 195 it('Should send a new video notification if the user follows the local video publisher', async function () {
195 this.timeout(15000) 196 this.timeout(15000)
196 197
197 await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:9001') 198 await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:' + servers[0].port)
198 await waitJobs(servers) 199 await waitJobs(servers)
199 200
200 const { name, uuid } = await uploadVideoByLocalAccount(servers) 201 const { name, uuid } = await uploadVideoByLocalAccount(servers)
@@ -204,7 +205,7 @@ describe('Test users notifications', function () {
204 it('Should send a new video notification from a remote account', async function () { 205 it('Should send a new video notification from a remote account', async function () {
205 this.timeout(50000) // Server 2 has transcoding enabled 206 this.timeout(50000) // Server 2 has transcoding enabled
206 207
207 await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:9002') 208 await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:' + servers[1].port)
208 await waitJobs(servers) 209 await waitJobs(servers)
209 210
210 const { name, uuid } = await uploadVideoByRemoteAccount(servers) 211 const { name, uuid } = await uploadVideoByRemoteAccount(servers)
@@ -578,7 +579,9 @@ describe('Test users notifications', function () {
578 const uuid = resVideo.body.video.uuid 579 const uuid = resVideo.body.video.uuid
579 580
580 await waitJobs(servers) 581 await waitJobs(servers)
581 const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, 'hello @user_1@localhost:9001 1') 582
583 const text1 = `hello @user_1@localhost:${servers[ 0 ].port} 1`
584 const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, text1)
582 const server2ThreadId = resThread.body.comment.id 585 const server2ThreadId = resThread.body.comment.id
583 586
584 await waitJobs(servers) 587 await waitJobs(servers)
@@ -588,8 +591,8 @@ describe('Test users notifications', function () {
588 const server1ThreadId = resThread2.body.data[0].id 591 const server1ThreadId = resThread2.body.data[0].id
589 await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence') 592 await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence')
590 593
591 const text = '@user_1@localhost:9001 hello 2 @root@localhost:9001' 594 const text2 = `@user_1@localhost:${servers[ 0 ].port} hello 2 @root@localhost:${servers[ 0 ].port}`
592 await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text) 595 await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text2)
593 596
594 await waitJobs(servers) 597 await waitJobs(servers)
595 598
@@ -889,10 +892,10 @@ describe('Test users notifications', function () {
889 892
890 await waitJobs(servers) 893 await waitJobs(servers)
891 894
892 await checkNewInstanceFollower(baseParams, 'localhost:9003', 'presence') 895 await checkNewInstanceFollower(baseParams, 'localhost:' + servers[2].port, 'presence')
893 896
894 const userOverride = { socketNotifications: userNotifications, token: userAccessToken, check: { web: true, mail: false } } 897 const userOverride = { socketNotifications: userNotifications, token: userAccessToken, check: { web: true, mail: false } }
895 await checkNewInstanceFollower(immutableAssign(baseParams, userOverride), 'localhost:9003', 'absence') 898 await checkNewInstanceFollower(immutableAssign(baseParams, userOverride), 'localhost:' + servers[2].port, 'absence')
896 }) 899 })
897 }) 900 })
898 901
@@ -933,29 +936,29 @@ describe('Test users notifications', function () {
933 it('Should notify when a local channel is following one of our channel', async function () { 936 it('Should notify when a local channel is following one of our channel', async function () {
934 this.timeout(10000) 937 this.timeout(10000)
935 938
936 await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001') 939 await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port)
937 await waitJobs(servers) 940 await waitJobs(servers)
938 941
939 await checkNewActorFollow(baseParams, 'channel', 'root', 'super root name', myChannelName, 'presence') 942 await checkNewActorFollow(baseParams, 'channel', 'root', 'super root name', myChannelName, 'presence')
940 943
941 await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001') 944 await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port)
942 }) 945 })
943 946
944 it('Should notify when a remote channel is following one of our channel', async function () { 947 it('Should notify when a remote channel is following one of our channel', async function () {
945 this.timeout(10000) 948 this.timeout(10000)
946 949
947 await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001') 950 await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port)
948 await waitJobs(servers) 951 await waitJobs(servers)
949 952
950 await checkNewActorFollow(baseParams, 'channel', 'root', 'super root 2 name', myChannelName, 'presence') 953 await checkNewActorFollow(baseParams, 'channel', 'root', 'super root 2 name', myChannelName, 'presence')
951 954
952 await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001') 955 await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port)
953 }) 956 })
954 957
955 it('Should notify when a local account is following one of our channel', async function () { 958 it('Should notify when a local account is following one of our channel', async function () {
956 this.timeout(10000) 959 this.timeout(10000)
957 960
958 await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1@localhost:9001') 961 await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1@localhost:' + servers[0].port)
959 962
960 await waitJobs(servers) 963 await waitJobs(servers)
961 964
@@ -965,7 +968,7 @@ describe('Test users notifications', function () {
965 it('Should notify when a remote account is following one of our channel', async function () { 968 it('Should notify when a remote account is following one of our channel', async function () {
966 this.timeout(10000) 969 this.timeout(10000)
967 970
968 await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1@localhost:9001') 971 await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1@localhost:' + servers[0].port)
969 972
970 await waitJobs(servers) 973 await waitJobs(servers)
971 974
@@ -1019,8 +1022,8 @@ describe('Test users notifications', function () {
1019 autoBlacklistTestsCustomConfig.transcoding.enabled = true 1022 autoBlacklistTestsCustomConfig.transcoding.enabled = true
1020 await updateCustomConfig(servers[0].url, servers[0].accessToken, autoBlacklistTestsCustomConfig) 1023 await updateCustomConfig(servers[0].url, servers[0].accessToken, autoBlacklistTestsCustomConfig)
1021 1024
1022 await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001') 1025 await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port)
1023 await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001') 1026 await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port)
1024 1027
1025 }) 1028 })
1026 1029
@@ -1142,8 +1145,8 @@ describe('Test users notifications', function () {
1142 after(async () => { 1145 after(async () => {
1143 await updateCustomConfig(servers[0].url, servers[0].accessToken, currentCustomConfig) 1146 await updateCustomConfig(servers[0].url, servers[0].accessToken, currentCustomConfig)
1144 1147
1145 await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:9001') 1148 await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port)
1146 await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:9001') 1149 await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port)
1147 }) 1150 })
1148 }) 1151 })
1149 1152
diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts
index e31329c25..6f2c59076 100644
--- a/server/tests/api/redundancy/redundancy.ts
+++ b/server/tests/api/redundancy/redundancy.ts
@@ -100,7 +100,7 @@ async function check1WebSeed (videoUUID?: string) {
100 if (!videoUUID) videoUUID = video1Server2UUID 100 if (!videoUUID) videoUUID = video1Server2UUID
101 101
102 const webseeds = [ 102 const webseeds = [
103 'http://localhost:9002/static/webseed/' + videoUUID 103 `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}`
104 ] 104 ]
105 105
106 for (const server of servers) { 106 for (const server of servers) {
@@ -118,8 +118,8 @@ async function check2Webseeds (videoUUID?: string) {
118 if (!videoUUID) videoUUID = video1Server2UUID 118 if (!videoUUID) videoUUID = video1Server2UUID
119 119
120 const webseeds = [ 120 const webseeds = [
121 'http://localhost:9001/static/redundancy/' + videoUUID, 121 `http://localhost:${servers[ 0 ].port}/static/redundancy/${videoUUID}`,
122 'http://localhost:9002/static/webseed/' + videoUUID 122 `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}`
123 ] 123 ]
124 124
125 for (const server of servers) { 125 for (const server of servers) {
@@ -145,7 +145,12 @@ async function check2Webseeds (videoUUID?: string) {
145 } 145 }
146 } 146 }
147 147
148 for (const directory of [ 'test1/redundancy', 'test2/videos' ]) { 148 const directories = [
149 'test' + servers[0].internalServerNumber + '/redundancy',
150 'test' + servers[1].internalServerNumber + '/videos'
151 ]
152
153 for (const directory of directories) {
149 const files = await readdir(join(root(), directory)) 154 const files = await readdir(join(root(), directory))
150 expect(files).to.have.length.at.least(4) 155 expect(files).to.have.length.at.least(4)
151 156
@@ -194,7 +199,12 @@ async function check1PlaylistRedundancies (videoUUID?: string) {
194 await checkSegmentHash(baseUrlPlaylist, baseUrlSegment, videoUUID, resolution, hlsPlaylist) 199 await checkSegmentHash(baseUrlPlaylist, baseUrlSegment, videoUUID, resolution, hlsPlaylist)
195 } 200 }
196 201
197 for (const directory of [ 'test1/redundancy/hls', 'test2/streaming-playlists/hls' ]) { 202 const directories = [
203 'test' + servers[0].internalServerNumber + '/redundancy/hls',
204 'test' + servers[1].internalServerNumber + '/streaming-playlists/hls'
205 ]
206
207 for (const directory of directories) {
198 const files = await readdir(join(root(), directory, videoUUID)) 208 const files = await readdir(join(root(), directory, videoUUID))
199 expect(files).to.have.length.at.least(4) 209 expect(files).to.have.length.at.least(4)
200 210
@@ -239,8 +249,8 @@ async function enableRedundancyOnServer1 () {
239 249
240 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt') 250 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt')
241 const follows: ActorFollow[] = res.body.data 251 const follows: ActorFollow[] = res.body.data
242 const server2 = follows.find(f => f.following.host === 'localhost:9002') 252 const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`)
243 const server3 = follows.find(f => f.following.host === 'localhost:9003') 253 const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`)
244 254
245 expect(server3).to.not.be.undefined 255 expect(server3).to.not.be.undefined
246 expect(server3.following.hostRedundancyAllowed).to.be.false 256 expect(server3.following.hostRedundancyAllowed).to.be.false
@@ -254,8 +264,8 @@ async function disableRedundancyOnServer1 () {
254 264
255 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt') 265 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt')
256 const follows: ActorFollow[] = res.body.data 266 const follows: ActorFollow[] = res.body.data
257 const server2 = follows.find(f => f.following.host === 'localhost:9002') 267 const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`)
258 const server3 = follows.find(f => f.following.host === 'localhost:9003') 268 const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`)
259 269
260 expect(server3).to.not.be.undefined 270 expect(server3).to.not.be.undefined
261 expect(server3.following.hostRedundancyAllowed).to.be.false 271 expect(server3.following.hostRedundancyAllowed).to.be.false
@@ -475,12 +485,12 @@ describe('Test videos redundancy', function () {
475 await wait(10000) 485 await wait(10000)
476 486
477 try { 487 try {
478 await checkContains(servers, 'http%3A%2F%2Flocalhost%3A9001') 488 await checkContains(servers, 'http%3A%2F%2Flocalhost%3A' + servers[0].port)
479 } catch { 489 } catch {
480 // Maybe a server deleted a redundancy in the scheduler 490 // Maybe a server deleted a redundancy in the scheduler
481 await wait(2000) 491 await wait(2000)
482 492
483 await checkContains(servers, 'http%3A%2F%2Flocalhost%3A9001') 493 await checkContains(servers, 'http%3A%2F%2Flocalhost%3A' + servers[0].port)
484 } 494 }
485 }) 495 })
486 496
@@ -491,7 +501,7 @@ describe('Test videos redundancy', function () {
491 501
492 await wait(15000) 502 await wait(15000)
493 503
494 await checkNotContains([ servers[1], servers[2] ], 'http%3A%2F%2Flocalhost%3A9001') 504 await checkNotContains([ servers[1], servers[2] ], 'http%3A%2F%2Flocalhost%3A' + servers[0].port)
495 }) 505 })
496 506
497 after(async function () { 507 after(async function () {
diff --git a/server/tests/api/search/search-activitypub-video-channels.ts b/server/tests/api/search/search-activitypub-video-channels.ts
index 4d1ceb767..8a008b8c6 100644
--- a/server/tests/api/search/search-activitypub-video-channels.ts
+++ b/server/tests/api/search/search-activitypub-video-channels.ts
@@ -3,16 +3,17 @@
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import {
6 addVideoChannel, cleanupTests, 6 addVideoChannel,
7 cleanupTests,
7 createUser, 8 createUser,
8 deleteVideoChannel, 9 deleteVideoChannel,
9 flushAndRunMultipleServers, 10 flushAndRunMultipleServers,
10 flushTests, 11 getVideoChannelsList,
11 getVideoChannelsList, getVideoChannelVideos, 12 getVideoChannelVideos,
12 killallServers,
13 ServerInfo, 13 ServerInfo,
14 setAccessTokensToServers, 14 setAccessTokensToServers,
15 updateMyUser, updateVideo, 15 updateMyUser,
16 updateVideo,
16 updateVideoChannel, 17 updateVideoChannel,
17 uploadVideo, 18 uploadVideo,
18 userLogin, 19 userLogin,
@@ -24,7 +25,7 @@ import { searchVideoChannel } from '../../../../shared/extra-utils/search/video-
24 25
25const expect = chai.expect 26const expect = chai.expect
26 27
27describe('Test a ActivityPub video channels search', function () { 28describe('Test ActivityPub video channels search', function () {
28 let servers: ServerInfo[] 29 let servers: ServerInfo[]
29 let userServer2Token: string 30 let userServer2Token: string
30 let videoServer2UUID: string 31 let videoServer2UUID: string
@@ -67,7 +68,7 @@ describe('Test a ActivityPub video channels search', function () {
67 68
68 it('Should not find a remote video channel', async function () { 69 it('Should not find a remote video channel', async function () {
69 { 70 {
70 const search = 'http://localhost:9002/video-channels/channel1_server3' 71 const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server3'
71 const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken) 72 const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken)
72 73
73 expect(res.body.total).to.equal(0) 74 expect(res.body.total).to.equal(0)
@@ -77,7 +78,7 @@ describe('Test a ActivityPub video channels search', function () {
77 78
78 { 79 {
79 // Without token 80 // Without token
80 const search = 'http://localhost:9002/video-channels/channel1_server2' 81 const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
81 const res = await searchVideoChannel(servers[0].url, search) 82 const res = await searchVideoChannel(servers[0].url, search)
82 83
83 expect(res.body.total).to.equal(0) 84 expect(res.body.total).to.equal(0)
@@ -88,8 +89,8 @@ describe('Test a ActivityPub video channels search', function () {
88 89
89 it('Should search a local video channel', async function () { 90 it('Should search a local video channel', async function () {
90 const searches = [ 91 const searches = [
91 'http://localhost:9001/video-channels/channel1_server1', 92 'http://localhost:' + servers[ 0 ].port + '/video-channels/channel1_server1',
92 'channel1_server1@localhost:9001' 93 'channel1_server1@localhost:' + servers[ 0 ].port
93 ] 94 ]
94 95
95 for (const search of searches) { 96 for (const search of searches) {
@@ -105,8 +106,8 @@ describe('Test a ActivityPub video channels search', function () {
105 106
106 it('Should search a remote video channel with URL or handle', async function () { 107 it('Should search a remote video channel with URL or handle', async function () {
107 const searches = [ 108 const searches = [
108 'http://localhost:9002/video-channels/channel1_server2', 109 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2',
109 'channel1_server2@localhost:9002' 110 'channel1_server2@localhost:' + servers[ 1 ].port
110 ] 111 ]
111 112
112 for (const search of searches) { 113 for (const search of searches) {
@@ -134,13 +135,13 @@ describe('Test a ActivityPub video channels search', function () {
134 135
135 await waitJobs(servers) 136 await waitJobs(servers)
136 137
137 const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:9002', 0, 5) 138 const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5)
138 expect(res.body.total).to.equal(0) 139 expect(res.body.total).to.equal(0)
139 expect(res.body.data).to.have.lengthOf(0) 140 expect(res.body.data).to.have.lengthOf(0)
140 }) 141 })
141 142
142 it('Should list video channel videos of server 2 with token', async function () { 143 it('Should list video channel videos of server 2 with token', async function () {
143 const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:9002', 0, 5) 144 const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5)
144 145
145 expect(res.body.total).to.equal(1) 146 expect(res.body.total).to.equal(1)
146 expect(res.body.data[0].name).to.equal('video 1 server 2') 147 expect(res.body.data[0].name).to.equal('video 1 server 2')
@@ -156,7 +157,7 @@ describe('Test a ActivityPub video channels search', function () {
156 // Expire video channel 157 // Expire video channel
157 await wait(10000) 158 await wait(10000)
158 159
159 const search = 'http://localhost:9002/video-channels/channel1_server2' 160 const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
160 const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) 161 const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
161 expect(res.body.total).to.equal(1) 162 expect(res.body.total).to.equal(1)
162 expect(res.body.data).to.have.lengthOf(1) 163 expect(res.body.data).to.have.lengthOf(1)
@@ -179,12 +180,13 @@ describe('Test a ActivityPub video channels search', function () {
179 // Expire video channel 180 // Expire video channel
180 await wait(10000) 181 await wait(10000)
181 182
182 const search = 'http://localhost:9002/video-channels/channel1_server2' 183 const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
183 await searchVideoChannel(servers[0].url, search, servers[0].accessToken) 184 await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
184 185
185 await waitJobs(servers) 186 await waitJobs(servers)
186 187
187 const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:9002', 0, 5, '-createdAt') 188 const videoChannelName = 'channel1_server2@localhost:' + servers[ 1 ].port
189 const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, videoChannelName, 0, 5, '-createdAt')
188 190
189 expect(res.body.total).to.equal(2) 191 expect(res.body.total).to.equal(2)
190 expect(res.body.data[0].name).to.equal('video 2 server 2') 192 expect(res.body.data[0].name).to.equal('video 2 server 2')
@@ -200,7 +202,8 @@ describe('Test a ActivityPub video channels search', function () {
200 // Expire video 202 // Expire video
201 await wait(10000) 203 await wait(10000)
202 204
203 const res = await searchVideoChannel(servers[0].url, 'http://localhost:9002/video-channels/channel1_server2', servers[0].accessToken) 205 const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
206 const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
204 expect(res.body.total).to.equal(0) 207 expect(res.body.total).to.equal(0)
205 expect(res.body.data).to.have.lengthOf(0) 208 expect(res.body.data).to.have.lengthOf(0)
206 }) 209 })
diff --git a/server/tests/api/search/search-activitypub-videos.ts b/server/tests/api/search/search-activitypub-videos.ts
index e039961cb..dbfefadda 100644
--- a/server/tests/api/search/search-activitypub-videos.ts
+++ b/server/tests/api/search/search-activitypub-videos.ts
@@ -4,25 +4,24 @@ import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import {
6 addVideoChannel, 6 addVideoChannel,
7 cleanupTests,
7 flushAndRunMultipleServers, 8 flushAndRunMultipleServers,
8 flushTests,
9 getVideosList, 9 getVideosList,
10 killallServers,
11 removeVideo, 10 removeVideo,
11 searchVideo,
12 searchVideoWithToken, 12 searchVideoWithToken,
13 ServerInfo, 13 ServerInfo,
14 setAccessTokensToServers, 14 setAccessTokensToServers,
15 updateVideo, 15 updateVideo,
16 uploadVideo, 16 uploadVideo,
17 wait, 17 wait
18 searchVideo, cleanupTests
19} from '../../../../shared/extra-utils' 18} from '../../../../shared/extra-utils'
20import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 19import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
21import { Video, VideoPrivacy } from '../../../../shared/models/videos' 20import { Video, VideoPrivacy } from '../../../../shared/models/videos'
22 21
23const expect = chai.expect 22const expect = chai.expect
24 23
25describe('Test a ActivityPub videos search', function () { 24describe('Test ActivityPub videos search', function () {
26 let servers: ServerInfo[] 25 let servers: ServerInfo[]
27 let videoServer1UUID: string 26 let videoServer1UUID: string
28 let videoServer2UUID: string 27 let videoServer2UUID: string
@@ -49,7 +48,8 @@ describe('Test a ActivityPub videos search', function () {
49 48
50 it('Should not find a remote video', async function () { 49 it('Should not find a remote video', async function () {
51 { 50 {
52 const res = await searchVideoWithToken(servers[ 0 ].url, 'http://localhost:9002/videos/watch/43', servers[ 0 ].accessToken) 51 const search = 'http://localhost:' + servers[1].port + '/videos/watch/43'
52 const res = await searchVideoWithToken(servers[ 0 ].url, search, servers[ 0 ].accessToken)
53 53
54 expect(res.body.total).to.equal(0) 54 expect(res.body.total).to.equal(0)
55 expect(res.body.data).to.be.an('array') 55 expect(res.body.data).to.be.an('array')
@@ -58,7 +58,8 @@ describe('Test a ActivityPub videos search', function () {
58 58
59 { 59 {
60 // Without token 60 // Without token
61 const res = await searchVideo(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID) 61 const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID
62 const res = await searchVideo(servers[0].url, search)
62 63
63 expect(res.body.total).to.equal(0) 64 expect(res.body.total).to.equal(0)
64 expect(res.body.data).to.be.an('array') 65 expect(res.body.data).to.be.an('array')
@@ -67,7 +68,8 @@ describe('Test a ActivityPub videos search', function () {
67 }) 68 })
68 69
69 it('Should search a local video', async function () { 70 it('Should search a local video', async function () {
70 const res = await searchVideo(servers[0].url, 'http://localhost:9001/videos/watch/' + videoServer1UUID) 71 const search = 'http://localhost:' + servers[0].port + '/videos/watch/' + videoServer1UUID
72 const res = await searchVideo(servers[0].url, search)
71 73
72 expect(res.body.total).to.equal(1) 74 expect(res.body.total).to.equal(1)
73 expect(res.body.data).to.be.an('array') 75 expect(res.body.data).to.be.an('array')
@@ -76,7 +78,8 @@ describe('Test a ActivityPub videos search', function () {
76 }) 78 })
77 79
78 it('Should search a remote video', async function () { 80 it('Should search a remote video', async function () {
79 const res = await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken) 81 const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID
82 const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
80 83
81 expect(res.body.total).to.equal(1) 84 expect(res.body.total).to.equal(1)
82 expect(res.body.data).to.be.an('array') 85 expect(res.body.data).to.be.an('array')
@@ -114,12 +117,13 @@ describe('Test a ActivityPub videos search', function () {
114 await wait(10000) 117 await wait(10000)
115 118
116 // Will run refresh async 119 // Will run refresh async
117 await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken) 120 const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID
121 await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
118 122
119 // Wait refresh 123 // Wait refresh
120 await wait(5000) 124 await wait(5000)
121 125
122 const res = await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken) 126 const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
123 expect(res.body.total).to.equal(1) 127 expect(res.body.total).to.equal(1)
124 expect(res.body.data).to.have.lengthOf(1) 128 expect(res.body.data).to.have.lengthOf(1)
125 129
@@ -139,12 +143,13 @@ describe('Test a ActivityPub videos search', function () {
139 await wait(10000) 143 await wait(10000)
140 144
141 // Will run refresh async 145 // Will run refresh async
142 await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken) 146 const search = 'http://localhost:' + servers[1].port + '/videos/watch/' + videoServer2UUID
147 await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
143 148
144 // Wait refresh 149 // Wait refresh
145 await wait(5000) 150 await wait(5000)
146 151
147 const res = await searchVideoWithToken(servers[0].url, 'http://localhost:9002/videos/watch/' + videoServer2UUID, servers[0].accessToken) 152 const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
148 expect(res.body.total).to.equal(0) 153 expect(res.body.total).to.equal(0)
149 expect(res.body.data).to.have.lengthOf(0) 154 expect(res.body.data).to.have.lengthOf(0)
150 }) 155 })
diff --git a/server/tests/api/search/search-videos.ts b/server/tests/api/search/search-videos.ts
index 1a086b33a..92cc0dc71 100644
--- a/server/tests/api/search/search-videos.ts
+++ b/server/tests/api/search/search-videos.ts
@@ -4,21 +4,19 @@ import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import {
6 advancedVideosSearch, 6 advancedVideosSearch,
7 flushTests, 7 cleanupTests,
8 killallServers,
9 flushAndRunServer, 8 flushAndRunServer,
9 immutableAssign,
10 searchVideo, 10 searchVideo,
11 ServerInfo, 11 ServerInfo,
12 setAccessTokensToServers, 12 setAccessTokensToServers,
13 uploadVideo, 13 uploadVideo,
14 wait, 14 wait
15 immutableAssign,
16 cleanupTests
17} from '../../../../shared/extra-utils' 15} from '../../../../shared/extra-utils'
18 16
19const expect = chai.expect 17const expect = chai.expect
20 18
21describe('Test a videos search', function () { 19describe('Test videos search', function () {
22 let server: ServerInfo = null 20 let server: ServerInfo = null
23 let startDate: string 21 let startDate: string
24 22
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts
index c0d11914b..8ea21158a 100644
--- a/server/tests/api/server/config.ts
+++ b/server/tests/api/server/config.ts
@@ -11,17 +11,17 @@ import {
11 getAbout, 11 getAbout,
12 getConfig, 12 getConfig,
13 getCustomConfig, 13 getCustomConfig,
14 killallServers, 14 killallServers, parallelTests,
15 registerUser, 15 registerUser,
16 reRunServer, 16 reRunServer, ServerInfo,
17 setAccessTokensToServers, 17 setAccessTokensToServers,
18 updateCustomConfig 18 updateCustomConfig, uploadVideo
19} from '../../../../shared/extra-utils' 19} from '../../../../shared/extra-utils'
20import { ServerConfig } from '../../../../shared/models' 20import { ServerConfig } from '../../../../shared/models'
21 21
22const expect = chai.expect 22const expect = chai.expect
23 23
24function checkInitialConfig (data: CustomConfig) { 24function checkInitialConfig (server: ServerInfo, data: CustomConfig) {
25 expect(data.instance.name).to.equal('PeerTube') 25 expect(data.instance.name).to.equal('PeerTube')
26 expect(data.instance.shortDescription).to.equal( 26 expect(data.instance.shortDescription).to.equal(
27 'PeerTube, a federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser ' + 27 'PeerTube, a federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser ' +
@@ -45,13 +45,14 @@ function checkInitialConfig (data: CustomConfig) {
45 expect(data.signup.limit).to.equal(4) 45 expect(data.signup.limit).to.equal(4)
46 expect(data.signup.requiresEmailVerification).to.be.false 46 expect(data.signup.requiresEmailVerification).to.be.false
47 47
48 expect(data.admin.email).to.equal('admin1@example.com') 48 expect(data.admin.email).to.equal('admin' + server.internalServerNumber + '@example.com')
49 expect(data.contactForm.enabled).to.be.true 49 expect(data.contactForm.enabled).to.be.true
50 50
51 expect(data.user.videoQuota).to.equal(5242880) 51 expect(data.user.videoQuota).to.equal(5242880)
52 expect(data.user.videoQuotaDaily).to.equal(-1) 52 expect(data.user.videoQuotaDaily).to.equal(-1)
53 expect(data.transcoding.enabled).to.be.false 53 expect(data.transcoding.enabled).to.be.false
54 expect(data.transcoding.allowAdditionalExtensions).to.be.false 54 expect(data.transcoding.allowAdditionalExtensions).to.be.false
55 expect(data.transcoding.allowAudioFiles).to.be.false
55 expect(data.transcoding.threads).to.equal(2) 56 expect(data.transcoding.threads).to.equal(2)
56 expect(data.transcoding.resolutions['240p']).to.be.true 57 expect(data.transcoding.resolutions['240p']).to.be.true
57 expect(data.transcoding.resolutions['360p']).to.be.true 58 expect(data.transcoding.resolutions['360p']).to.be.true
@@ -89,7 +90,11 @@ function checkUpdatedConfig (data: CustomConfig) {
89 expect(data.signup.limit).to.equal(5) 90 expect(data.signup.limit).to.equal(5)
90 expect(data.signup.requiresEmailVerification).to.be.false 91 expect(data.signup.requiresEmailVerification).to.be.false
91 92
92 expect(data.admin.email).to.equal('superadmin1@example.com') 93 // We override admin email in parallel tests, so skip this exception
94 if (parallelTests() === false) {
95 expect(data.admin.email).to.equal('superadmin1@example.com')
96 }
97
93 expect(data.contactForm.enabled).to.be.false 98 expect(data.contactForm.enabled).to.be.false
94 99
95 expect(data.user.videoQuota).to.equal(5242881) 100 expect(data.user.videoQuota).to.equal(5242881)
@@ -98,6 +103,7 @@ function checkUpdatedConfig (data: CustomConfig) {
98 expect(data.transcoding.enabled).to.be.true 103 expect(data.transcoding.enabled).to.be.true
99 expect(data.transcoding.threads).to.equal(1) 104 expect(data.transcoding.threads).to.equal(1)
100 expect(data.transcoding.allowAdditionalExtensions).to.be.true 105 expect(data.transcoding.allowAdditionalExtensions).to.be.true
106 expect(data.transcoding.allowAudioFiles).to.be.true
101 expect(data.transcoding.resolutions['240p']).to.be.false 107 expect(data.transcoding.resolutions['240p']).to.be.false
102 expect(data.transcoding.resolutions['360p']).to.be.true 108 expect(data.transcoding.resolutions['360p']).to.be.true
103 expect(data.transcoding.resolutions['480p']).to.be.true 109 expect(data.transcoding.resolutions['480p']).to.be.true
@@ -118,6 +124,7 @@ describe('Test config', function () {
118 124
119 before(async function () { 125 before(async function () {
120 this.timeout(30000) 126 this.timeout(30000)
127
121 server = await flushAndRunServer(1) 128 server = await flushAndRunServer(1)
122 await setAccessTokensToServers([ server ]) 129 await setAccessTokensToServers([ server ])
123 }) 130 })
@@ -153,6 +160,9 @@ describe('Test config', function () {
153 expect(data.video.file.extensions).to.contain('.webm') 160 expect(data.video.file.extensions).to.contain('.webm')
154 expect(data.video.file.extensions).to.contain('.ogv') 161 expect(data.video.file.extensions).to.contain('.ogv')
155 162
163 await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, 400)
164 await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, 400)
165
156 expect(data.contactForm.enabled).to.be.true 166 expect(data.contactForm.enabled).to.be.true
157 }) 167 })
158 168
@@ -160,7 +170,7 @@ describe('Test config', function () {
160 const res = await getCustomConfig(server.url, server.accessToken) 170 const res = await getCustomConfig(server.url, server.accessToken)
161 const data = res.body as CustomConfig 171 const data = res.body as CustomConfig
162 172
163 checkInitialConfig(data) 173 checkInitialConfig(server, data)
164 }) 174 })
165 175
166 it('Should update the customized configuration', async function () { 176 it('Should update the customized configuration', async function () {
@@ -210,6 +220,7 @@ describe('Test config', function () {
210 transcoding: { 220 transcoding: {
211 enabled: true, 221 enabled: true,
212 allowAdditionalExtensions: true, 222 allowAdditionalExtensions: true,
223 allowAudioFiles: true,
213 threads: 1, 224 threads: 1,
214 resolutions: { 225 resolutions: {
215 '240p': false, 226 '240p': false,
@@ -264,6 +275,12 @@ describe('Test config', function () {
264 expect(data.video.file.extensions).to.contain('.ogv') 275 expect(data.video.file.extensions).to.contain('.ogv')
265 expect(data.video.file.extensions).to.contain('.flv') 276 expect(data.video.file.extensions).to.contain('.flv')
266 expect(data.video.file.extensions).to.contain('.mkv') 277 expect(data.video.file.extensions).to.contain('.mkv')
278 expect(data.video.file.extensions).to.contain('.mp3')
279 expect(data.video.file.extensions).to.contain('.ogg')
280 expect(data.video.file.extensions).to.contain('.flac')
281
282 await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, 200)
283 await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, 200)
267 }) 284 })
268 285
269 it('Should have the configuration updated after a restart', async function () { 286 it('Should have the configuration updated after a restart', async function () {
@@ -297,7 +314,7 @@ describe('Test config', function () {
297 const res = await getCustomConfig(server.url, server.accessToken) 314 const res = await getCustomConfig(server.url, server.accessToken)
298 const data = res.body 315 const data = res.body
299 316
300 checkInitialConfig(data) 317 checkInitialConfig(server, data)
301 }) 318 })
302 319
303 after(async function () { 320 after(async function () {
diff --git a/server/tests/api/server/contact-form.ts b/server/tests/api/server/contact-form.ts
index ba51198b3..87e55060c 100644
--- a/server/tests/api/server/contact-form.ts
+++ b/server/tests/api/server/contact-form.ts
@@ -24,11 +24,12 @@ describe('Test contact form', function () {
24 before(async function () { 24 before(async function () {
25 this.timeout(30000) 25 this.timeout(30000)
26 26
27 await MockSmtpServer.Instance.collectEmails(emails) 27 const port = await MockSmtpServer.Instance.collectEmails(emails)
28 28
29 const overrideConfig = { 29 const overrideConfig = {
30 smtp: { 30 smtp: {
31 hostname: 'localhost' 31 hostname: 'localhost',
32 port
32 } 33 }
33 } 34 }
34 server = await flushAndRunServer(1, overrideConfig) 35 server = await flushAndRunServer(1, overrideConfig)
@@ -53,7 +54,7 @@ describe('Test contact form', function () {
53 54
54 expect(email['from'][0]['address']).equal('test-admin@localhost') 55 expect(email['from'][0]['address']).equal('test-admin@localhost')
55 expect(email['from'][0]['name']).equal('toto@example.com') 56 expect(email['from'][0]['name']).equal('toto@example.com')
56 expect(email['to'][0]['address']).equal('admin1@example.com') 57 expect(email['to'][0]['address']).equal('admin' + server.internalServerNumber + '@example.com')
57 expect(email['subject']).contains('Contact form') 58 expect(email['subject']).contains('Contact form')
58 expect(email['text']).contains('my super message') 59 expect(email['text']).contains('my super message')
59 }) 60 })
diff --git a/server/tests/api/server/email.ts b/server/tests/api/server/email.ts
index bacdf1b1b..5929a3adb 100644
--- a/server/tests/api/server/email.ts
+++ b/server/tests/api/server/email.ts
@@ -7,18 +7,18 @@ import {
7 askResetPassword, 7 askResetPassword,
8 askSendVerifyEmail, 8 askSendVerifyEmail,
9 blockUser, 9 blockUser,
10 createUser, removeVideoFromBlacklist, 10 cleanupTests,
11 createUser,
12 flushAndRunServer,
13 removeVideoFromBlacklist,
11 reportVideoAbuse, 14 reportVideoAbuse,
12 resetPassword, 15 resetPassword,
13 flushAndRunServer, 16 ServerInfo,
17 setAccessTokensToServers,
14 unblockUser, 18 unblockUser,
15 uploadVideo, 19 uploadVideo,
16 userLogin, 20 userLogin,
17 verifyEmail, 21 verifyEmail
18 flushTests,
19 killallServers,
20 ServerInfo,
21 setAccessTokensToServers, cleanupTests
22} from '../../../../shared/extra-utils' 22} from '../../../../shared/extra-utils'
23import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' 23import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
24import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 24import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
@@ -37,15 +37,17 @@ describe('Test emails', function () {
37 username: 'user_1', 37 username: 'user_1',
38 password: 'super_password' 38 password: 'super_password'
39 } 39 }
40 let emailPort: number
40 41
41 before(async function () { 42 before(async function () {
42 this.timeout(30000) 43 this.timeout(30000)
43 44
44 await MockSmtpServer.Instance.collectEmails(emails) 45 emailPort = await MockSmtpServer.Instance.collectEmails(emails)
45 46
46 const overrideConfig = { 47 const overrideConfig = {
47 smtp: { 48 smtp: {
48 hostname: 'localhost' 49 hostname: 'localhost',
50 port: emailPort
49 } 51 }
50 } 52 }
51 server = await flushAndRunServer(1, overrideConfig) 53 server = await flushAndRunServer(1, overrideConfig)
@@ -87,7 +89,7 @@ describe('Test emails', function () {
87 89
88 const email = emails[0] 90 const email = emails[0]
89 91
90 expect(email['from'][0]['name']).equal('localhost:9001') 92 expect(email['from'][0]['name']).equal('localhost:' + server.port)
91 expect(email['from'][0]['address']).equal('test-admin@localhost') 93 expect(email['from'][0]['address']).equal('test-admin@localhost')
92 expect(email['to'][0]['address']).equal('user_1@example.com') 94 expect(email['to'][0]['address']).equal('user_1@example.com')
93 expect(email['subject']).contains('password') 95 expect(email['subject']).contains('password')
@@ -132,9 +134,9 @@ describe('Test emails', function () {
132 134
133 const email = emails[1] 135 const email = emails[1]
134 136
135 expect(email['from'][0]['name']).equal('localhost:9001') 137 expect(email['from'][0]['name']).equal('localhost:' + server.port)
136 expect(email['from'][0]['address']).equal('test-admin@localhost') 138 expect(email['from'][0]['address']).equal('test-admin@localhost')
137 expect(email['to'][0]['address']).equal('admin1@example.com') 139 expect(email['to'][0]['address']).equal('admin' + server.internalServerNumber + '@example.com')
138 expect(email['subject']).contains('abuse') 140 expect(email['subject']).contains('abuse')
139 expect(email['text']).contains(videoUUID) 141 expect(email['text']).contains(videoUUID)
140 }) 142 })
@@ -153,7 +155,7 @@ describe('Test emails', function () {
153 155
154 const email = emails[2] 156 const email = emails[2]
155 157
156 expect(email['from'][0]['name']).equal('localhost:9001') 158 expect(email['from'][0]['name']).equal('localhost:' + server.port)
157 expect(email['from'][0]['address']).equal('test-admin@localhost') 159 expect(email['from'][0]['address']).equal('test-admin@localhost')
158 expect(email['to'][0]['address']).equal('user_1@example.com') 160 expect(email['to'][0]['address']).equal('user_1@example.com')
159 expect(email['subject']).contains(' blocked') 161 expect(email['subject']).contains(' blocked')
@@ -171,7 +173,7 @@ describe('Test emails', function () {
171 173
172 const email = emails[3] 174 const email = emails[3]
173 175
174 expect(email['from'][0]['name']).equal('localhost:9001') 176 expect(email['from'][0]['name']).equal('localhost:' + server.port)
175 expect(email['from'][0]['address']).equal('test-admin@localhost') 177 expect(email['from'][0]['address']).equal('test-admin@localhost')
176 expect(email['to'][0]['address']).equal('user_1@example.com') 178 expect(email['to'][0]['address']).equal('user_1@example.com')
177 expect(email['subject']).contains(' unblocked') 179 expect(email['subject']).contains(' unblocked')
@@ -191,7 +193,7 @@ describe('Test emails', function () {
191 193
192 const email = emails[4] 194 const email = emails[4]
193 195
194 expect(email['from'][0]['name']).equal('localhost:9001') 196 expect(email['from'][0]['name']).equal('localhost:' + server.port)
195 expect(email['from'][0]['address']).equal('test-admin@localhost') 197 expect(email['from'][0]['address']).equal('test-admin@localhost')
196 expect(email['to'][0]['address']).equal('user_1@example.com') 198 expect(email['to'][0]['address']).equal('user_1@example.com')
197 expect(email['subject']).contains(' blacklisted') 199 expect(email['subject']).contains(' blacklisted')
@@ -209,7 +211,7 @@ describe('Test emails', function () {
209 211
210 const email = emails[5] 212 const email = emails[5]
211 213
212 expect(email['from'][0]['name']).equal('localhost:9001') 214 expect(email['from'][0]['name']).equal('localhost:' + server.port)
213 expect(email['from'][0]['address']).equal('test-admin@localhost') 215 expect(email['from'][0]['address']).equal('test-admin@localhost')
214 expect(email['to'][0]['address']).equal('user_1@example.com') 216 expect(email['to'][0]['address']).equal('user_1@example.com')
215 expect(email['subject']).contains(' unblacklisted') 217 expect(email['subject']).contains(' unblacklisted')
@@ -229,7 +231,7 @@ describe('Test emails', function () {
229 231
230 const email = emails[6] 232 const email = emails[6]
231 233
232 expect(email['from'][0]['name']).equal('localhost:9001') 234 expect(email['from'][0]['name']).equal('localhost:' + server.port)
233 expect(email['from'][0]['address']).equal('test-admin@localhost') 235 expect(email['from'][0]['address']).equal('test-admin@localhost')
234 expect(email['to'][0]['address']).equal('user_1@example.com') 236 expect(email['to'][0]['address']).equal('user_1@example.com')
235 expect(email['subject']).contains('Verify') 237 expect(email['subject']).contains('Verify')
diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts
index 4285a9e7a..ac3ff37f0 100644
--- a/server/tests/api/server/follow-constraints.ts
+++ b/server/tests/api/server/follow-constraints.ts
@@ -3,16 +3,16 @@
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import {
6 cleanupTests,
6 doubleFollow, 7 doubleFollow,
8 flushAndRunMultipleServers,
7 getAccountVideos, 9 getAccountVideos,
8 getVideo, 10 getVideo,
9 getVideoChannelVideos, 11 getVideoChannelVideos,
10 getVideoWithToken, 12 getVideoWithToken,
11 flushAndRunMultipleServers,
12 killallServers,
13 ServerInfo, 13 ServerInfo,
14 setAccessTokensToServers, 14 setAccessTokensToServers,
15 uploadVideo, cleanupTests 15 uploadVideo
16} from '../../../../shared/extra-utils' 16} from '../../../../shared/extra-utils'
17import { unfollow } from '../../../../shared/extra-utils/server/follows' 17import { unfollow } from '../../../../shared/extra-utils/server/follows'
18import { userLogin } from '../../../../shared/extra-utils/users/login' 18import { userLogin } from '../../../../shared/extra-utils/users/login'
@@ -66,28 +66,30 @@ describe('Test follow constraints', function () {
66 }) 66 })
67 67
68 it('Should list local account videos', async function () { 68 it('Should list local account videos', async function () {
69 const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9001', 0, 5) 69 const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[0].port, 0, 5)
70 70
71 expect(res.body.total).to.equal(1) 71 expect(res.body.total).to.equal(1)
72 expect(res.body.data).to.have.lengthOf(1) 72 expect(res.body.data).to.have.lengthOf(1)
73 }) 73 })
74 74
75 it('Should list remote account videos', async function () { 75 it('Should list remote account videos', async function () {
76 const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9002', 0, 5) 76 const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[1].port, 0, 5)
77 77
78 expect(res.body.total).to.equal(1) 78 expect(res.body.total).to.equal(1)
79 expect(res.body.data).to.have.lengthOf(1) 79 expect(res.body.data).to.have.lengthOf(1)
80 }) 80 })
81 81
82 it('Should list local channel videos', async function () { 82 it('Should list local channel videos', async function () {
83 const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9001', 0, 5) 83 const videoChannelName = 'root_channel@localhost:' + servers[0].port
84 const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5)
84 85
85 expect(res.body.total).to.equal(1) 86 expect(res.body.total).to.equal(1)
86 expect(res.body.data).to.have.lengthOf(1) 87 expect(res.body.data).to.have.lengthOf(1)
87 }) 88 })
88 89
89 it('Should list remote channel videos', async function () { 90 it('Should list remote channel videos', async function () {
90 const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9002', 0, 5) 91 const videoChannelName = 'root_channel@localhost:' + servers[1].port
92 const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5)
91 93
92 expect(res.body.total).to.equal(1) 94 expect(res.body.total).to.equal(1)
93 expect(res.body.data).to.have.lengthOf(1) 95 expect(res.body.data).to.have.lengthOf(1)
@@ -104,28 +106,30 @@ describe('Test follow constraints', function () {
104 }) 106 })
105 107
106 it('Should list local account videos', async function () { 108 it('Should list local account videos', async function () {
107 const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9001', 0, 5) 109 const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[0].port, 0, 5)
108 110
109 expect(res.body.total).to.equal(1) 111 expect(res.body.total).to.equal(1)
110 expect(res.body.data).to.have.lengthOf(1) 112 expect(res.body.data).to.have.lengthOf(1)
111 }) 113 })
112 114
113 it('Should list remote account videos', async function () { 115 it('Should list remote account videos', async function () {
114 const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9002', 0, 5) 116 const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[1].port, 0, 5)
115 117
116 expect(res.body.total).to.equal(1) 118 expect(res.body.total).to.equal(1)
117 expect(res.body.data).to.have.lengthOf(1) 119 expect(res.body.data).to.have.lengthOf(1)
118 }) 120 })
119 121
120 it('Should list local channel videos', async function () { 122 it('Should list local channel videos', async function () {
121 const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9001', 0, 5) 123 const videoChannelName = 'root_channel@localhost:' + servers[0].port
124 const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5)
122 125
123 expect(res.body.total).to.equal(1) 126 expect(res.body.total).to.equal(1)
124 expect(res.body.data).to.have.lengthOf(1) 127 expect(res.body.data).to.have.lengthOf(1)
125 }) 128 })
126 129
127 it('Should list remote channel videos', async function () { 130 it('Should list remote channel videos', async function () {
128 const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9002', 0, 5) 131 const videoChannelName = 'root_channel@localhost:' + servers[1].port
132 const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5)
129 133
130 expect(res.body.total).to.equal(1) 134 expect(res.body.total).to.equal(1)
131 expect(res.body.data).to.have.lengthOf(1) 135 expect(res.body.data).to.have.lengthOf(1)
@@ -152,28 +156,30 @@ describe('Test follow constraints', function () {
152 }) 156 })
153 157
154 it('Should list local account videos', async function () { 158 it('Should list local account videos', async function () {
155 const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9001', 0, 5) 159 const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[0].port, 0, 5)
156 160
157 expect(res.body.total).to.equal(1) 161 expect(res.body.total).to.equal(1)
158 expect(res.body.data).to.have.lengthOf(1) 162 expect(res.body.data).to.have.lengthOf(1)
159 }) 163 })
160 164
161 it('Should not list remote account videos', async function () { 165 it('Should not list remote account videos', async function () {
162 const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:9002', 0, 5) 166 const res = await getAccountVideos(servers[0].url, undefined, 'root@localhost:' + servers[1].port, 0, 5)
163 167
164 expect(res.body.total).to.equal(0) 168 expect(res.body.total).to.equal(0)
165 expect(res.body.data).to.have.lengthOf(0) 169 expect(res.body.data).to.have.lengthOf(0)
166 }) 170 })
167 171
168 it('Should list local channel videos', async function () { 172 it('Should list local channel videos', async function () {
169 const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9001', 0, 5) 173 const videoChannelName = 'root_channel@localhost:' + servers[0].port
174 const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5)
170 175
171 expect(res.body.total).to.equal(1) 176 expect(res.body.total).to.equal(1)
172 expect(res.body.data).to.have.lengthOf(1) 177 expect(res.body.data).to.have.lengthOf(1)
173 }) 178 })
174 179
175 it('Should not list remote channel videos', async function () { 180 it('Should not list remote channel videos', async function () {
176 const res = await getVideoChannelVideos(servers[0].url, undefined, 'root_channel@localhost:9002', 0, 5) 181 const videoChannelName = 'root_channel@localhost:' + servers[1].port
182 const res = await getVideoChannelVideos(servers[0].url, undefined, videoChannelName, 0, 5)
177 183
178 expect(res.body.total).to.equal(0) 184 expect(res.body.total).to.equal(0)
179 expect(res.body.data).to.have.lengthOf(0) 185 expect(res.body.data).to.have.lengthOf(0)
@@ -190,28 +196,30 @@ describe('Test follow constraints', function () {
190 }) 196 })
191 197
192 it('Should list local account videos', async function () { 198 it('Should list local account videos', async function () {
193 const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9001', 0, 5) 199 const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[0].port, 0, 5)
194 200
195 expect(res.body.total).to.equal(1) 201 expect(res.body.total).to.equal(1)
196 expect(res.body.data).to.have.lengthOf(1) 202 expect(res.body.data).to.have.lengthOf(1)
197 }) 203 })
198 204
199 it('Should list remote account videos', async function () { 205 it('Should list remote account videos', async function () {
200 const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:9002', 0, 5) 206 const res = await getAccountVideos(servers[0].url, userAccessToken, 'root@localhost:' + servers[1].port, 0, 5)
201 207
202 expect(res.body.total).to.equal(1) 208 expect(res.body.total).to.equal(1)
203 expect(res.body.data).to.have.lengthOf(1) 209 expect(res.body.data).to.have.lengthOf(1)
204 }) 210 })
205 211
206 it('Should list local channel videos', async function () { 212 it('Should list local channel videos', async function () {
207 const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9001', 0, 5) 213 const videoChannelName = 'root_channel@localhost:' + servers[0].port
214 const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5)
208 215
209 expect(res.body.total).to.equal(1) 216 expect(res.body.total).to.equal(1)
210 expect(res.body.data).to.have.lengthOf(1) 217 expect(res.body.data).to.have.lengthOf(1)
211 }) 218 })
212 219
213 it('Should list remote channel videos', async function () { 220 it('Should list remote channel videos', async function () {
214 const res = await getVideoChannelVideos(servers[0].url, userAccessToken, 'root_channel@localhost:9002', 0, 5) 221 const videoChannelName = 'root_channel@localhost:' + servers[1].port
222 const res = await getVideoChannelVideos(servers[0].url, userAccessToken, videoChannelName, 0, 5)
215 223
216 expect(res.body.total).to.equal(1) 224 expect(res.body.total).to.equal(1)
217 expect(res.body.data).to.have.lengthOf(1) 225 expect(res.body.data).to.have.lengthOf(1)
diff --git a/server/tests/api/server/follows-moderation.ts b/server/tests/api/server/follows-moderation.ts
index 2a3a4d5c8..a82acdb34 100644
--- a/server/tests/api/server/follows-moderation.ts
+++ b/server/tests/api/server/follows-moderation.ts
@@ -3,9 +3,9 @@
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import {
6 acceptFollower, cleanupTests, 6 acceptFollower,
7 cleanupTests,
7 flushAndRunMultipleServers, 8 flushAndRunMultipleServers,
8 killallServers,
9 ServerInfo, 9 ServerInfo,
10 setAccessTokensToServers, 10 setAccessTokensToServers,
11 updateCustomSubConfig 11 updateCustomSubConfig
@@ -14,8 +14,8 @@ import {
14 follow, 14 follow,
15 getFollowersListPaginationAndSort, 15 getFollowersListPaginationAndSort,
16 getFollowingListPaginationAndSort, 16 getFollowingListPaginationAndSort,
17 removeFollower, 17 rejectFollower,
18 rejectFollower 18 removeFollower
19} from '../../../../shared/extra-utils/server/follows' 19} from '../../../../shared/extra-utils/server/follows'
20import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 20import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
21import { ActorFollow } from '../../../../shared/models/actors' 21import { ActorFollow } from '../../../../shared/models/actors'
@@ -29,8 +29,8 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc
29 29
30 const follow = res.body.data[0] as ActorFollow 30 const follow = res.body.data[0] as ActorFollow
31 expect(follow.state).to.equal(state) 31 expect(follow.state).to.equal(state)
32 expect(follow.follower.url).to.equal('http://localhost:9001/accounts/peertube') 32 expect(follow.follower.url).to.equal('http://localhost:' + servers[0].port + '/accounts/peertube')
33 expect(follow.following.url).to.equal('http://localhost:9002/accounts/peertube') 33 expect(follow.following.url).to.equal('http://localhost:' + servers[1].port + '/accounts/peertube')
34 } 34 }
35 35
36 { 36 {
@@ -39,8 +39,8 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc
39 39
40 const follow = res.body.data[0] as ActorFollow 40 const follow = res.body.data[0] as ActorFollow
41 expect(follow.state).to.equal(state) 41 expect(follow.state).to.equal(state)
42 expect(follow.follower.url).to.equal('http://localhost:9001/accounts/peertube') 42 expect(follow.follower.url).to.equal('http://localhost:' + servers[0].port + '/accounts/peertube')
43 expect(follow.following.url).to.equal('http://localhost:9002/accounts/peertube') 43 expect(follow.following.url).to.equal('http://localhost:' + servers[1].port + '/accounts/peertube')
44 } 44 }
45} 45}
46 46
@@ -151,7 +151,7 @@ describe('Test follows moderation', function () {
151 }) 151 })
152 152
153 it('Should accept a follower', async function () { 153 it('Should accept a follower', async function () {
154 await acceptFollower(servers[1].url, servers[1].accessToken, 'peertube@localhost:9001') 154 await acceptFollower(servers[1].url, servers[1].accessToken, 'peertube@localhost:' + servers[0].port)
155 await waitJobs(servers) 155 await waitJobs(servers)
156 156
157 await checkServer1And2HasFollowers(servers) 157 await checkServer1And2HasFollowers(servers)
@@ -178,7 +178,7 @@ describe('Test follows moderation', function () {
178 expect(res.body.total).to.equal(1) 178 expect(res.body.total).to.equal(1)
179 } 179 }
180 180
181 await rejectFollower(servers[2].url, servers[2].accessToken, 'peertube@localhost:9001') 181 await rejectFollower(servers[2].url, servers[2].accessToken, 'peertube@localhost:' + servers[0].port)
182 await waitJobs(servers) 182 await waitJobs(servers)
183 183
184 await checkServer1And2HasFollowers(servers) 184 await checkServer1And2HasFollowers(servers)
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts
index 397093cdb..e8d6f5138 100644
--- a/server/tests/api/server/follows.ts
+++ b/server/tests/api/server/follows.ts
@@ -8,7 +8,6 @@ import { cleanupTests, completeVideoCheck } from '../../../../shared/extra-utils
8import { 8import {
9 flushAndRunMultipleServers, 9 flushAndRunMultipleServers,
10 getVideosList, 10 getVideosList,
11 killallServers,
12 ServerInfo, 11 ServerInfo,
13 setAccessTokensToServers, 12 setAccessTokensToServers,
14 uploadVideo 13 uploadVideo
@@ -89,8 +88,8 @@ describe('Test follows', function () {
89 res = await getFollowingListPaginationAndSort(servers[0].url, 1, 1, 'createdAt') 88 res = await getFollowingListPaginationAndSort(servers[0].url, 1, 1, 'createdAt')
90 follows = follows.concat(res.body.data) 89 follows = follows.concat(res.body.data)
91 90
92 const server2Follow = follows.find(f => f.following.host === 'localhost:9002') 91 const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port)
93 const server3Follow = follows.find(f => f.following.host === 'localhost:9003') 92 const server3Follow = follows.find(f => f.following.host === 'localhost:' + servers[2].port)
94 93
95 expect(server2Follow).to.not.be.undefined 94 expect(server2Follow).to.not.be.undefined
96 expect(server3Follow).to.not.be.undefined 95 expect(server3Follow).to.not.be.undefined
@@ -100,12 +99,12 @@ describe('Test follows', function () {
100 99
101 it('Should search followings on server 1', async function () { 100 it('Should search followings on server 1', async function () {
102 { 101 {
103 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', ':9002') 102 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', ':' + servers[1].port)
104 const follows = res.body.data 103 const follows = res.body.data
105 104
106 expect(res.body.total).to.equal(1) 105 expect(res.body.total).to.equal(1)
107 expect(follows.length).to.equal(1) 106 expect(follows.length).to.equal(1)
108 expect(follows[ 0 ].following.host).to.equal('localhost:9002') 107 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[1].port)
109 } 108 }
110 109
111 { 110 {
@@ -136,18 +135,18 @@ describe('Test follows', function () {
136 expect(res.body.total).to.equal(1) 135 expect(res.body.total).to.equal(1)
137 expect(follows).to.be.an('array') 136 expect(follows).to.be.an('array')
138 expect(follows.length).to.equal(1) 137 expect(follows.length).to.equal(1)
139 expect(follows[0].follower.host).to.equal('localhost:9001') 138 expect(follows[0].follower.host).to.equal('localhost:' + servers[0].port)
140 } 139 }
141 }) 140 })
142 141
143 it('Should search followers on server 2', async function () { 142 it('Should search followers on server 2', async function () {
144 { 143 {
145 const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', '9001') 144 const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', servers[0].port + '')
146 const follows = res.body.data 145 const follows = res.body.data
147 146
148 expect(res.body.total).to.equal(1) 147 expect(res.body.total).to.equal(1)
149 expect(follows.length).to.equal(1) 148 expect(follows.length).to.equal(1)
150 expect(follows[ 0 ].following.host).to.equal('localhost:9003') 149 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[2].port)
151 } 150 }
152 151
153 { 152 {
@@ -169,16 +168,16 @@ describe('Test follows', function () {
169 }) 168 })
170 169
171 it('Should have the correct follows counts', async function () { 170 it('Should have the correct follows counts', async function () {
172 await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 2) 171 await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[0].port, 0, 2)
173 await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0) 172 await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[1].port, 1, 0)
174 await expectAccountFollows(servers[0].url, 'peertube@localhost:9003', 1, 0) 173 await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[2].port, 1, 0)
175 174
176 // Server 2 and 3 does not know server 1 follow another server (there was not a refresh) 175 // Server 2 and 3 does not know server 1 follow another server (there was not a refresh)
177 await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1) 176 await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[0].port, 0, 1)
178 await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0) 177 await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[1].port, 1, 0)
179 178
180 await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 1) 179 await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[0].port, 0, 1)
181 await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 1, 0) 180 await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[2].port, 1, 0)
182 }) 181 })
183 182
184 it('Should unfollow server 3 on server 1', async function () { 183 it('Should unfollow server 3 on server 1', async function () {
@@ -197,7 +196,7 @@ describe('Test follows', function () {
197 expect(follows).to.be.an('array') 196 expect(follows).to.be.an('array')
198 expect(follows.length).to.equal(1) 197 expect(follows.length).to.equal(1)
199 198
200 expect(follows[0].following.host).to.equal('localhost:9002') 199 expect(follows[0].following.host).to.equal('localhost:' + servers[1].port)
201 }) 200 })
202 201
203 it('Should not have server 1 as follower on server 3 anymore', async function () { 202 it('Should not have server 1 as follower on server 3 anymore', async function () {
@@ -210,14 +209,14 @@ describe('Test follows', function () {
210 }) 209 })
211 210
212 it('Should have the correct follows counts 2', async function () { 211 it('Should have the correct follows counts 2', async function () {
213 await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 1) 212 await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[0].port, 0, 1)
214 await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0) 213 await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[1].port, 1, 0)
215 214
216 await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1) 215 await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[0].port, 0, 1)
217 await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0) 216 await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[1].port, 1, 0)
218 217
219 await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 0) 218 await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[0].port, 0, 0)
220 await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 0, 0) 219 await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[2].port, 0, 0)
221 }) 220 })
222 221
223 it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () { 222 it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () {
@@ -310,15 +309,15 @@ describe('Test follows', function () {
310 }) 309 })
311 310
312 it('Should have the correct follows counts 3', async function () { 311 it('Should have the correct follows counts 3', async function () {
313 await expectAccountFollows(servers[0].url, 'peertube@localhost:9001', 0, 2) 312 await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[0].port, 0, 2)
314 await expectAccountFollows(servers[0].url, 'peertube@localhost:9002', 1, 0) 313 await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[1].port, 1, 0)
315 await expectAccountFollows(servers[0].url, 'peertube@localhost:9003', 1, 0) 314 await expectAccountFollows(servers[0].url, 'peertube@localhost:' + servers[2].port, 1, 0)
316 315
317 await expectAccountFollows(servers[1].url, 'peertube@localhost:9001', 0, 1) 316 await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[0].port, 0, 1)
318 await expectAccountFollows(servers[1].url, 'peertube@localhost:9002', 1, 0) 317 await expectAccountFollows(servers[1].url, 'peertube@localhost:' + servers[1].port, 1, 0)
319 318
320 await expectAccountFollows(servers[2].url, 'peertube@localhost:9001', 0, 2) 319 await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[0].port, 0, 2)
321 await expectAccountFollows(servers[2].url, 'peertube@localhost:9003', 1, 0) 320 await expectAccountFollows(servers[2].url, 'peertube@localhost:' + servers[2].port, 1, 0)
322 }) 321 })
323 322
324 it('Should have propagated videos', async function () { 323 it('Should have propagated videos', async function () {
@@ -344,7 +343,7 @@ describe('Test follows', function () {
344 support: 'my super support text', 343 support: 'my super support text',
345 account: { 344 account: {
346 name: 'root', 345 name: 'root',
347 host: 'localhost:9003' 346 host: 'localhost:' + servers[2].port
348 }, 347 },
349 isLocal, 348 isLocal,
350 commentsEnabled: true, 349 commentsEnabled: true,
@@ -384,7 +383,7 @@ describe('Test follows', function () {
384 expect(comment.videoId).to.equal(video4.id) 383 expect(comment.videoId).to.equal(video4.id)
385 expect(comment.id).to.equal(comment.threadId) 384 expect(comment.id).to.equal(comment.threadId)
386 expect(comment.account.name).to.equal('root') 385 expect(comment.account.name).to.equal('root')
387 expect(comment.account.host).to.equal('localhost:9003') 386 expect(comment.account.host).to.equal('localhost:' + servers[2].port)
388 expect(comment.totalReplies).to.equal(3) 387 expect(comment.totalReplies).to.equal(3)
389 expect(dateIsValid(comment.createdAt as string)).to.be.true 388 expect(dateIsValid(comment.createdAt as string)).to.be.true
390 expect(dateIsValid(comment.updatedAt as string)).to.be.true 389 expect(dateIsValid(comment.updatedAt as string)).to.be.true
diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts
index 19010dbc1..068654d8c 100644
--- a/server/tests/api/server/handle-down.ts
+++ b/server/tests/api/server/handle-down.ts
@@ -60,48 +60,50 @@ describe('Test handle downs', function () {
60 privacy: VideoPrivacy.UNLISTED 60 privacy: VideoPrivacy.UNLISTED
61 }) 61 })
62 62
63 const checkAttributes = { 63 let checkAttributes: any
64 name: 'my super name for server 1', 64 let unlistedCheckAttributes: any
65 category: 5,
66 licence: 4,
67 language: 'ja',
68 nsfw: true,
69 description: 'my super description for server 1',
70 support: 'my super support text for server 1',
71 account: {
72 name: 'root',
73 host: 'localhost:9001'
74 },
75 isLocal: false,
76 duration: 10,
77 tags: [ 'tag1p1', 'tag2p1' ],
78 privacy: VideoPrivacy.PUBLIC,
79 commentsEnabled: true,
80 downloadEnabled: true,
81 channel: {
82 name: 'root_channel',
83 displayName: 'Main root channel',
84 description: '',
85 isLocal: false
86 },
87 fixture: 'video_short1.webm',
88 files: [
89 {
90 resolution: 720,
91 size: 572456
92 }
93 ]
94 }
95
96 const unlistedCheckAttributes = immutableAssign(checkAttributes, {
97 privacy: VideoPrivacy.UNLISTED
98 })
99 65
100 before(async function () { 66 before(async function () {
101 this.timeout(30000) 67 this.timeout(30000)
102 68
103 servers = await flushAndRunMultipleServers(3) 69 servers = await flushAndRunMultipleServers(3)
104 70
71 checkAttributes = {
72 name: 'my super name for server 1',
73 category: 5,
74 licence: 4,
75 language: 'ja',
76 nsfw: true,
77 description: 'my super description for server 1',
78 support: 'my super support text for server 1',
79 account: {
80 name: 'root',
81 host: 'localhost:' + servers[0].port
82 },
83 isLocal: false,
84 duration: 10,
85 tags: [ 'tag1p1', 'tag2p1' ],
86 privacy: VideoPrivacy.PUBLIC,
87 commentsEnabled: true,
88 downloadEnabled: true,
89 channel: {
90 name: 'root_channel',
91 displayName: 'Main root channel',
92 description: '',
93 isLocal: false
94 },
95 fixture: 'video_short1.webm',
96 files: [
97 {
98 resolution: 720,
99 size: 572456
100 }
101 ]
102 }
103 unlistedCheckAttributes = immutableAssign(checkAttributes, {
104 privacy: VideoPrivacy.UNLISTED
105 })
106
105 // Get the access tokens 107 // Get the access tokens
106 await setAccessTokensToServers(servers) 108 await setAccessTokensToServers(servers)
107 }) 109 })
@@ -172,7 +174,7 @@ describe('Test handle downs', function () {
172 const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 2, 'createdAt') 174 const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 2, 'createdAt')
173 expect(res.body.data).to.be.an('array') 175 expect(res.body.data).to.be.an('array')
174 expect(res.body.data).to.have.lengthOf(1) 176 expect(res.body.data).to.have.lengthOf(1)
175 expect(res.body.data[0].follower.host).to.equal('localhost:9003') 177 expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port)
176 }) 178 })
177 179
178 it('Should not have pending/processing jobs anymore', async function () { 180 it('Should not have pending/processing jobs anymore', async function () {
diff --git a/server/tests/api/server/jobs.ts b/server/tests/api/server/jobs.ts
index 634654626..3ab2fe120 100644
--- a/server/tests/api/server/jobs.ts
+++ b/server/tests/api/server/jobs.ts
@@ -26,7 +26,7 @@ describe('Test jobs', function () {
26 }) 26 })
27 27
28 it('Should create some jobs', async function () { 28 it('Should create some jobs', async function () {
29 this.timeout(30000) 29 this.timeout(60000)
30 30
31 await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video1' }) 31 await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video1' })
32 await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video2' }) 32 await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video2' })
diff --git a/server/tests/api/server/logs.ts b/server/tests/api/server/logs.ts
index 3644fa0d3..68f442199 100644
--- a/server/tests/api/server/logs.ts
+++ b/server/tests/api/server/logs.ts
@@ -45,7 +45,7 @@ describe('Test logs', function () {
45 }) 45 })
46 46
47 it('Should get logs with an end date', async function () { 47 it('Should get logs with an end date', async function () {
48 this.timeout(10000) 48 this.timeout(20000)
49 49
50 await uploadVideo(server.url, server.accessToken, { name: 'video 3' }) 50 await uploadVideo(server.url, server.accessToken, { name: 'video 3' })
51 await waitJobs([ server ]) 51 await waitJobs([ server ])
diff --git a/server/tests/api/travis-1.sh b/server/tests/api/travis-1.sh
new file mode 100644
index 000000000..db4021b25
--- /dev/null
+++ b/server/tests/api/travis-1.sh
@@ -0,0 +1,10 @@
1#!/usr/bin/env sh
2
3set -eu
4
5checkParamFiles=$(find server/tests/api/check-params -type f | grep -v index.ts | xargs echo)
6notificationsFiles=$(find server/tests/api/notifications -type f | grep -v index.ts | xargs echo)
7searchFiles=$(find server/tests/api/search -type f | grep -v index.ts | xargs echo)
8
9MOCHA_PARALLEL=true mocha --timeout 5000 --exit --require ts-node/register --bail \
10 $notificationsFiles $searchFiles $checkParamFiles
diff --git a/server/tests/api/travis-2.sh b/server/tests/api/travis-2.sh
new file mode 100644
index 000000000..ba7a061b0
--- /dev/null
+++ b/server/tests/api/travis-2.sh
@@ -0,0 +1,9 @@
1#!/usr/bin/env sh
2
3set -eu
4
5serverFiles=$(find server/tests/api/server -type f | grep -v index.ts | xargs echo)
6usersFiles=$(find server/tests/api/users -type f | grep -v index.ts | xargs echo)
7
8MOCHA_PARALLEL=true mocha --timeout 5000 --exit --require ts-node/register --bail \
9 $serverFiles $usersFiles
diff --git a/server/tests/api/travis-3.sh b/server/tests/api/travis-3.sh
new file mode 100644
index 000000000..82457222c
--- /dev/null
+++ b/server/tests/api/travis-3.sh
@@ -0,0 +1,8 @@
1#!/usr/bin/env sh
2
3set -eu
4
5videosFiles=$(find server/tests/api/videos -type f | grep -v index.ts | xargs echo)
6
7MOCHA_PARALLEL=true mocha --timeout 5000 --exit --require ts-node/register --bail \
8 $videosFiles
diff --git a/server/tests/api/travis-4.sh b/server/tests/api/travis-4.sh
new file mode 100644
index 000000000..875986182
--- /dev/null
+++ b/server/tests/api/travis-4.sh
@@ -0,0 +1,9 @@
1#!/usr/bin/env sh
2
3set -eu
4
5redundancyFiles=$(find server/tests/api/redundancy -type f | grep -v index.ts | xargs echo)
6activitypubFiles=$(find server/tests/api/activitypub -type f | grep -v index.ts | xargs echo)
7
8MOCHA_PARALLEL=true mocha-parallel-tests --max-parallel $1 --timeout 5000 --exit --require ts-node/register --bail \
9 $redundancyFiles $activitypubFiles
diff --git a/server/tests/api/users/blocklist.ts b/server/tests/api/users/blocklist.ts
index fbc57e0ef..c25e85ada 100644
--- a/server/tests/api/users/blocklist.ts
+++ b/server/tests/api/users/blocklist.ts
@@ -144,7 +144,7 @@ describe('Test blocklist', function () {
144 }) 144 })
145 145
146 it('Should block a remote account', async function () { 146 it('Should block a remote account', async function () {
147 await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002') 147 await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
148 }) 148 })
149 149
150 it('Should hide its videos', async function () { 150 it('Should hide its videos', async function () {
@@ -209,7 +209,7 @@ describe('Test blocklist', function () {
209 expect(block.byAccount.name).to.equal('root') 209 expect(block.byAccount.name).to.equal('root')
210 expect(block.blockedAccount.displayName).to.equal('user2') 210 expect(block.blockedAccount.displayName).to.equal('user2')
211 expect(block.blockedAccount.name).to.equal('user2') 211 expect(block.blockedAccount.name).to.equal('user2')
212 expect(block.blockedAccount.host).to.equal('localhost:9002') 212 expect(block.blockedAccount.host).to.equal('localhost:' + servers[1].port)
213 } 213 }
214 214
215 { 215 {
@@ -223,12 +223,12 @@ describe('Test blocklist', function () {
223 expect(block.byAccount.name).to.equal('root') 223 expect(block.byAccount.name).to.equal('root')
224 expect(block.blockedAccount.displayName).to.equal('user1') 224 expect(block.blockedAccount.displayName).to.equal('user1')
225 expect(block.blockedAccount.name).to.equal('user1') 225 expect(block.blockedAccount.name).to.equal('user1')
226 expect(block.blockedAccount.host).to.equal('localhost:9001') 226 expect(block.blockedAccount.host).to.equal('localhost:' + servers[0].port)
227 } 227 }
228 }) 228 })
229 229
230 it('Should unblock the remote account', async function () { 230 it('Should unblock the remote account', async function () {
231 await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002') 231 await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
232 }) 232 })
233 233
234 it('Should display its videos', async function () { 234 it('Should display its videos', async function () {
@@ -260,7 +260,7 @@ describe('Test blocklist', function () {
260 }) 260 })
261 261
262 it('Should block a remote server', async function () { 262 it('Should block a remote server', async function () {
263 await addServerToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002') 263 await addServerToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
264 }) 264 })
265 265
266 it('Should hide its videos', async function () { 266 it('Should hide its videos', async function () {
@@ -291,11 +291,11 @@ describe('Test blocklist', function () {
291 const block = blocks[ 0 ] 291 const block = blocks[ 0 ]
292 expect(block.byAccount.displayName).to.equal('root') 292 expect(block.byAccount.displayName).to.equal('root')
293 expect(block.byAccount.name).to.equal('root') 293 expect(block.byAccount.name).to.equal('root')
294 expect(block.blockedServer.host).to.equal('localhost:9002') 294 expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port)
295 }) 295 })
296 296
297 it('Should unblock the remote server', async function () { 297 it('Should unblock the remote server', async function () {
298 await removeServerFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002') 298 await removeServerFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
299 }) 299 })
300 300
301 it('Should display its videos', function () { 301 it('Should display its videos', function () {
@@ -324,7 +324,7 @@ describe('Test blocklist', function () {
324 }) 324 })
325 325
326 it('Should block a remote account', async function () { 326 it('Should block a remote account', async function () {
327 await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002') 327 await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
328 }) 328 })
329 329
330 it('Should hide its videos', async function () { 330 it('Should hide its videos', async function () {
@@ -387,7 +387,7 @@ describe('Test blocklist', function () {
387 expect(block.byAccount.name).to.equal('peertube') 387 expect(block.byAccount.name).to.equal('peertube')
388 expect(block.blockedAccount.displayName).to.equal('user2') 388 expect(block.blockedAccount.displayName).to.equal('user2')
389 expect(block.blockedAccount.name).to.equal('user2') 389 expect(block.blockedAccount.name).to.equal('user2')
390 expect(block.blockedAccount.host).to.equal('localhost:9002') 390 expect(block.blockedAccount.host).to.equal('localhost:' + servers[1].port)
391 } 391 }
392 392
393 { 393 {
@@ -401,12 +401,12 @@ describe('Test blocklist', function () {
401 expect(block.byAccount.name).to.equal('peertube') 401 expect(block.byAccount.name).to.equal('peertube')
402 expect(block.blockedAccount.displayName).to.equal('user1') 402 expect(block.blockedAccount.displayName).to.equal('user1')
403 expect(block.blockedAccount.name).to.equal('user1') 403 expect(block.blockedAccount.name).to.equal('user1')
404 expect(block.blockedAccount.host).to.equal('localhost:9001') 404 expect(block.blockedAccount.host).to.equal('localhost:' + servers[0].port)
405 } 405 }
406 }) 406 })
407 407
408 it('Should unblock the remote account', async function () { 408 it('Should unblock the remote account', async function () {
409 await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:9002') 409 await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
410 }) 410 })
411 411
412 it('Should display its videos', async function () { 412 it('Should display its videos', async function () {
@@ -446,7 +446,7 @@ describe('Test blocklist', function () {
446 }) 446 })
447 447
448 it('Should block a remote server', async function () { 448 it('Should block a remote server', async function () {
449 await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002') 449 await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
450 }) 450 })
451 451
452 it('Should hide its videos', async function () { 452 it('Should hide its videos', async function () {
@@ -478,11 +478,11 @@ describe('Test blocklist', function () {
478 const block = blocks[ 0 ] 478 const block = blocks[ 0 ]
479 expect(block.byAccount.displayName).to.equal('peertube') 479 expect(block.byAccount.displayName).to.equal('peertube')
480 expect(block.byAccount.name).to.equal('peertube') 480 expect(block.byAccount.name).to.equal('peertube')
481 expect(block.blockedServer.host).to.equal('localhost:9002') 481 expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port)
482 }) 482 })
483 483
484 it('Should unblock the remote server', async function () { 484 it('Should unblock the remote server', async function () {
485 await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:9002') 485 await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
486 }) 486 })
487 487
488 it('Should list all videos', async function () { 488 it('Should list all videos', async function () {
diff --git a/server/tests/api/users/user-subscriptions.ts b/server/tests/api/users/user-subscriptions.ts
index 48811e647..c8a89d6be 100644
--- a/server/tests/api/users/user-subscriptions.ts
+++ b/server/tests/api/users/user-subscriptions.ts
@@ -71,8 +71,8 @@ describe('Test users subscriptions', function () {
71 it('User of server 1 should follow user of server 3 and root of server 1', async function () { 71 it('User of server 1 should follow user of server 3 and root of server 1', async function () {
72 this.timeout(60000) 72 this.timeout(60000)
73 73
74 await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003') 74 await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port)
75 await addUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:9001') 75 await addUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:' + servers[0].port)
76 76
77 await waitJobs(servers) 77 await waitJobs(servers)
78 78
@@ -116,22 +116,22 @@ describe('Test users subscriptions', function () {
116 116
117 it('Should get subscription', async function () { 117 it('Should get subscription', async function () {
118 { 118 {
119 const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:9003') 119 const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:' + servers[2].port)
120 const videoChannel: VideoChannel = res.body 120 const videoChannel: VideoChannel = res.body
121 121
122 expect(videoChannel.name).to.equal('user3_channel') 122 expect(videoChannel.name).to.equal('user3_channel')
123 expect(videoChannel.host).to.equal('localhost:9003') 123 expect(videoChannel.host).to.equal('localhost:' + servers[2].port)
124 expect(videoChannel.displayName).to.equal('Main user3 channel') 124 expect(videoChannel.displayName).to.equal('Main user3 channel')
125 expect(videoChannel.followingCount).to.equal(0) 125 expect(videoChannel.followingCount).to.equal(0)
126 expect(videoChannel.followersCount).to.equal(1) 126 expect(videoChannel.followersCount).to.equal(1)
127 } 127 }
128 128
129 { 129 {
130 const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:9001') 130 const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:' + servers[0].port)
131 const videoChannel: VideoChannel = res.body 131 const videoChannel: VideoChannel = res.body
132 132
133 expect(videoChannel.name).to.equal('root_channel') 133 expect(videoChannel.name).to.equal('root_channel')
134 expect(videoChannel.host).to.equal('localhost:9001') 134 expect(videoChannel.host).to.equal('localhost:' + servers[0].port)
135 expect(videoChannel.displayName).to.equal('Main root channel') 135 expect(videoChannel.displayName).to.equal('Main root channel')
136 expect(videoChannel.followingCount).to.equal(0) 136 expect(videoChannel.followingCount).to.equal(0)
137 expect(videoChannel.followersCount).to.equal(1) 137 expect(videoChannel.followersCount).to.equal(1)
@@ -140,19 +140,19 @@ describe('Test users subscriptions', function () {
140 140
141 it('Should return the existing subscriptions', async function () { 141 it('Should return the existing subscriptions', async function () {
142 const uris = [ 142 const uris = [
143 'user3_channel@localhost:9003', 143 'user3_channel@localhost:' + servers[2].port,
144 'root2_channel@localhost:9001', 144 'root2_channel@localhost:' + servers[0].port,
145 'root_channel@localhost:9001', 145 'root_channel@localhost:' + servers[0].port,
146 'user3_channel@localhost:9001' 146 'user3_channel@localhost:' + servers[0].port
147 ] 147 ]
148 148
149 const res = await areSubscriptionsExist(servers[ 0 ].url, users[ 0 ].accessToken, uris) 149 const res = await areSubscriptionsExist(servers[ 0 ].url, users[ 0 ].accessToken, uris)
150 const body = res.body 150 const body = res.body
151 151
152 expect(body['user3_channel@localhost:9003']).to.be.true 152 expect(body['user3_channel@localhost:' + servers[2].port]).to.be.true
153 expect(body['root2_channel@localhost:9001']).to.be.false 153 expect(body['root2_channel@localhost:' + servers[0].port]).to.be.false
154 expect(body['root_channel@localhost:9001']).to.be.true 154 expect(body['root_channel@localhost:' + servers[0].port]).to.be.true
155 expect(body['user3_channel@localhost:9001']).to.be.false 155 expect(body['user3_channel@localhost:' + servers[0].port]).to.be.false
156 }) 156 })
157 157
158 it('Should list subscription videos', async function () { 158 it('Should list subscription videos', async function () {
@@ -291,7 +291,7 @@ describe('Test users subscriptions', function () {
291 it('Should remove user of server 3 subscription', async function () { 291 it('Should remove user of server 3 subscription', async function () {
292 this.timeout(30000) 292 this.timeout(30000)
293 293
294 await removeUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003') 294 await removeUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port)
295 295
296 await waitJobs(servers) 296 await waitJobs(servers)
297 }) 297 })
@@ -312,7 +312,7 @@ describe('Test users subscriptions', function () {
312 it('Should remove the root subscription and not display the videos anymore', async function () { 312 it('Should remove the root subscription and not display the videos anymore', async function () {
313 this.timeout(30000) 313 this.timeout(30000)
314 314
315 await removeUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:9001') 315 await removeUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:' + servers[0].port)
316 316
317 await waitJobs(servers) 317 await waitJobs(servers)
318 318
@@ -340,7 +340,7 @@ describe('Test users subscriptions', function () {
340 it('Should follow user of server 3 again', async function () { 340 it('Should follow user of server 3 again', async function () {
341 this.timeout(60000) 341 this.timeout(60000)
342 342
343 await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:9003') 343 await addUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port)
344 344
345 await waitJobs(servers) 345 await waitJobs(servers)
346 346
diff --git a/server/tests/api/users/users-multiple-servers.ts b/server/tests/api/users/users-multiple-servers.ts
index 9a971adb3..791418318 100644
--- a/server/tests/api/users/users-multiple-servers.ts
+++ b/server/tests/api/users/users-multiple-servers.ts
@@ -5,7 +5,8 @@ import 'mocha'
5import { Account } from '../../../../shared/models/actors' 5import { Account } from '../../../../shared/models/actors'
6import { 6import {
7 checkTmpIsEmpty, 7 checkTmpIsEmpty,
8 checkVideoFilesWereRemoved, cleanupTests, 8 checkVideoFilesWereRemoved,
9 cleanupTests,
9 createUser, 10 createUser,
10 doubleFollow, 11 doubleFollow,
11 flushAndRunMultipleServers, 12 flushAndRunMultipleServers,
@@ -15,14 +16,7 @@ import {
15 updateMyUser, 16 updateMyUser,
16 userLogin 17 userLogin
17} from '../../../../shared/extra-utils' 18} from '../../../../shared/extra-utils'
18import { 19import { getMyUserInformation, ServerInfo, testImage, updateMyAvatar, uploadVideo } from '../../../../shared/extra-utils/index'
19 getMyUserInformation,
20 killallServers,
21 ServerInfo,
22 testImage,
23 updateMyAvatar,
24 uploadVideo
25} from '../../../../shared/extra-utils/index'
26import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../../../shared/extra-utils/users/accounts' 20import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../../../shared/extra-utils/users/accounts'
27import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' 21import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
28import { User } from '../../../../shared/models/users' 22import { User } from '../../../../shared/models/users'
@@ -34,12 +28,10 @@ const expect = chai.expect
34describe('Test users with multiple servers', function () { 28describe('Test users with multiple servers', function () {
35 let servers: ServerInfo[] = [] 29 let servers: ServerInfo[] = []
36 let user: User 30 let user: User
37 let userAccountName: string
38 let userAccountUUID: string
39 let userVideoChannelUUID: string
40 let userId: number 31 let userId: number
41 let videoUUID: string 32 let videoUUID: string
42 let userAccessToken: string 33 let userAccessToken: string
34 let userAvatarFilename: string
43 35
44 before(async function () { 36 before(async function () {
45 this.timeout(120000) 37 this.timeout(120000)
@@ -75,19 +67,6 @@ describe('Test users with multiple servers', function () {
75 } 67 }
76 68
77 { 69 {
78 const res = await getMyUserInformation(servers[0].url, userAccessToken)
79 const account: Account = res.body.account
80 userAccountName = account.name + '@' + account.host
81 userAccountUUID = account.uuid
82 }
83
84 {
85 const res = await getMyUserInformation(servers[ 0 ].url, servers[ 0 ].accessToken)
86 const user: User = res.body
87 userVideoChannelUUID = user.videoChannels[0].uuid
88 }
89
90 {
91 const resVideo = await uploadVideo(servers[ 0 ].url, userAccessToken, {}) 70 const resVideo = await uploadVideo(servers[ 0 ].url, userAccessToken, {})
92 videoUUID = resVideo.body.video.uuid 71 videoUUID = resVideo.body.video.uuid
93 } 72 }
@@ -106,6 +85,8 @@ describe('Test users with multiple servers', function () {
106 85
107 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) 86 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
108 user = res.body 87 user = res.body
88
89 const account: Account = user.account
109 expect(user.account.displayName).to.equal('my super display name') 90 expect(user.account.displayName).to.equal('my super display name')
110 91
111 await waitJobs(servers) 92 await waitJobs(servers)
@@ -142,7 +123,9 @@ describe('Test users with multiple servers', function () {
142 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) 123 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
143 user = res.body 124 user = res.body
144 125
145 await testImage(servers[0].url, 'avatar2-resized', user.account.avatar.path, '.png') 126 userAvatarFilename = user.account.avatar.path
127
128 await testImage(servers[0].url, 'avatar2-resized', userAvatarFilename, '.png')
146 129
147 await waitJobs(servers) 130 await waitJobs(servers)
148 }) 131 })
@@ -151,13 +134,13 @@ describe('Test users with multiple servers', function () {
151 for (const server of servers) { 134 for (const server of servers) {
152 const resAccounts = await getAccountsList(server.url, '-createdAt') 135 const resAccounts = await getAccountsList(server.url, '-createdAt')
153 136
154 const rootServer1List = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:9001') as Account 137 const rootServer1List = resAccounts.body.data.find(a => a.name === 'root' && a.host === 'localhost:' + servers[0].port) as Account
155 expect(rootServer1List).not.to.be.undefined 138 expect(rootServer1List).not.to.be.undefined
156 139
157 const resAccount = await getAccount(server.url, rootServer1List.name + '@' + rootServer1List.host) 140 const resAccount = await getAccount(server.url, rootServer1List.name + '@' + rootServer1List.host)
158 const rootServer1Get = resAccount.body as Account 141 const rootServer1Get = resAccount.body as Account
159 expect(rootServer1Get.name).to.equal('root') 142 expect(rootServer1Get.name).to.equal('root')
160 expect(rootServer1Get.host).to.equal('localhost:9001') 143 expect(rootServer1Get.host).to.equal('localhost:' + servers[0].port)
161 expect(rootServer1Get.displayName).to.equal('my super display name') 144 expect(rootServer1Get.displayName).to.equal('my super display name')
162 expect(rootServer1Get.description).to.equal('my super description updated') 145 expect(rootServer1Get.description).to.equal('my super description updated')
163 146
@@ -173,7 +156,7 @@ describe('Test users with multiple servers', function () {
173 156
174 it('Should list account videos', async function () { 157 it('Should list account videos', async function () {
175 for (const server of servers) { 158 for (const server of servers) {
176 const res = await getAccountVideos(server.url, server.accessToken, userAccountName, 0, 5) 159 const res = await getAccountVideos(server.url, server.accessToken, 'user1@localhost:' + servers[0].port, 0, 5)
177 160
178 expect(res.body.total).to.equal(1) 161 expect(res.body.total).to.equal(1)
179 expect(res.body.data).to.be.an('array') 162 expect(res.body.data).to.be.an('array')
@@ -188,12 +171,12 @@ describe('Test users with multiple servers', function () {
188 for (const server of servers) { 171 for (const server of servers) {
189 const resAccounts = await getAccountsList(server.url, '-createdAt') 172 const resAccounts = await getAccountsList(server.url, '-createdAt')
190 173
191 const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:9001') as Account 174 const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:' + servers[0].port) as Account
192 expect(accountDeleted).not.to.be.undefined 175 expect(accountDeleted).not.to.be.undefined
193 176
194 const resVideoChannels = await getVideoChannelsList(server.url, 0, 10) 177 const resVideoChannels = await getVideoChannelsList(server.url, 0, 10)
195 const videoChannelDeleted = resVideoChannels.body.data.find(a => { 178 const videoChannelDeleted = resVideoChannels.body.data.find(a => {
196 return a.displayName === 'Main user1 channel' && a.host === 'localhost:9001' 179 return a.displayName === 'Main user1 channel' && a.host === 'localhost:' + servers[0].port
197 }) as VideoChannel 180 }) as VideoChannel
198 expect(videoChannelDeleted).not.to.be.undefined 181 expect(videoChannelDeleted).not.to.be.undefined
199 } 182 }
@@ -205,12 +188,12 @@ describe('Test users with multiple servers', function () {
205 for (const server of servers) { 188 for (const server of servers) {
206 const resAccounts = await getAccountsList(server.url, '-createdAt') 189 const resAccounts = await getAccountsList(server.url, '-createdAt')
207 190
208 const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:9001') as Account 191 const accountDeleted = resAccounts.body.data.find(a => a.name === 'user1' && a.host === 'localhost:' + servers[0].port) as Account
209 expect(accountDeleted).to.be.undefined 192 expect(accountDeleted).to.be.undefined
210 193
211 const resVideoChannels = await getVideoChannelsList(server.url, 0, 10) 194 const resVideoChannels = await getVideoChannelsList(server.url, 0, 10)
212 const videoChannelDeleted = resVideoChannels.body.data.find(a => { 195 const videoChannelDeleted = resVideoChannels.body.data.find(a => {
213 return a.name === 'Main user1 channel' && a.host === 'localhost:9001' 196 return a.name === 'Main user1 channel' && a.host === 'localhost:' + servers[0].port
214 }) as VideoChannel 197 }) as VideoChannel
215 expect(videoChannelDeleted).to.be.undefined 198 expect(videoChannelDeleted).to.be.undefined
216 } 199 }
@@ -218,14 +201,13 @@ describe('Test users with multiple servers', function () {
218 201
219 it('Should not have actor files', async () => { 202 it('Should not have actor files', async () => {
220 for (const server of servers) { 203 for (const server of servers) {
221 await checkActorFilesWereRemoved(userAccountUUID, server.serverNumber) 204 await checkActorFilesWereRemoved(userAvatarFilename, server.internalServerNumber)
222 await checkActorFilesWereRemoved(userVideoChannelUUID, server.serverNumber)
223 } 205 }
224 }) 206 })
225 207
226 it('Should not have video files', async () => { 208 it('Should not have video files', async () => {
227 for (const server of servers) { 209 for (const server of servers) {
228 await checkVideoFilesWereRemoved(videoUUID, server.serverNumber) 210 await checkVideoFilesWereRemoved(videoUUID, server.internalServerNumber)
229 } 211 }
230 }) 212 })
231 213
diff --git a/server/tests/api/users/users-verification.ts b/server/tests/api/users/users-verification.ts
index 514acf2e7..3b37a26cf 100644
--- a/server/tests/api/users/users-verification.ts
+++ b/server/tests/api/users/users-verification.ts
@@ -30,11 +30,12 @@ describe('Test users account verification', function () {
30 before(async function () { 30 before(async function () {
31 this.timeout(30000) 31 this.timeout(30000)
32 32
33 await MockSmtpServer.Instance.collectEmails(emails) 33 const port = await MockSmtpServer.Instance.collectEmails(emails)
34 34
35 const overrideConfig = { 35 const overrideConfig = {
36 smtp: { 36 smtp: {
37 hostname: 'localhost' 37 hostname: 'localhost',
38 port
38 } 39 }
39 } 40 }
40 server = await flushAndRunServer(1, overrideConfig) 41 server = await flushAndRunServer(1, overrideConfig)
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts
index c8e32f3f5..9d2ef786f 100644
--- a/server/tests/api/users/users.ts
+++ b/server/tests/api/users/users.ts
@@ -31,7 +31,8 @@ import {
31 updateMyUser, 31 updateMyUser,
32 updateUser, 32 updateUser,
33 uploadVideo, 33 uploadVideo,
34 userLogin 34 userLogin,
35 registerUserWithChannel, getVideoChannel
35} from '../../../../shared/extra-utils' 36} from '../../../../shared/extra-utils'
36import { follow } from '../../../../shared/extra-utils/server/follows' 37import { follow } from '../../../../shared/extra-utils/server/follows'
37import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' 38import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
@@ -316,7 +317,7 @@ describe('Test users', function () {
316 317
317 const rootUser = users[ 1 ] 318 const rootUser = users[ 1 ]
318 expect(rootUser.username).to.equal('root') 319 expect(rootUser.username).to.equal('root')
319 expect(rootUser.email).to.equal('admin1@example.com') 320 expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com')
320 expect(user.nsfwPolicy).to.equal('display') 321 expect(user.nsfwPolicy).to.equal('display')
321 322
322 userId = user.id 323 userId = user.id
@@ -334,7 +335,7 @@ describe('Test users', function () {
334 335
335 const user = users[ 0 ] 336 const user = users[ 0 ]
336 expect(user.username).to.equal('root') 337 expect(user.username).to.equal('root')
337 expect(user.email).to.equal('admin1@example.com') 338 expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com')
338 expect(user.roleLabel).to.equal('Administrator') 339 expect(user.roleLabel).to.equal('Administrator')
339 expect(user.nsfwPolicy).to.equal('display') 340 expect(user.nsfwPolicy).to.equal('display')
340 }) 341 })
@@ -379,7 +380,7 @@ describe('Test users', function () {
379 expect(users.length).to.equal(2) 380 expect(users.length).to.equal(2)
380 381
381 expect(users[ 0 ].username).to.equal('root') 382 expect(users[ 0 ].username).to.equal('root')
382 expect(users[ 0 ].email).to.equal('admin1@example.com') 383 expect(users[ 0 ].email).to.equal('admin' + server.internalServerNumber + '@example.com')
383 expect(users[ 0 ].nsfwPolicy).to.equal('display') 384 expect(users[ 0 ].nsfwPolicy).to.equal('display')
384 385
385 expect(users[ 1 ].username).to.equal('user_1') 386 expect(users[ 1 ].username).to.equal('user_1')
@@ -617,7 +618,10 @@ describe('Test users', function () {
617 618
618 describe('Registering a new user', function () { 619 describe('Registering a new user', function () {
619 it('Should register a new user', async function () { 620 it('Should register a new user', async function () {
620 await registerUser(server.url, 'user_15', 'my super password') 621 const user = { username: 'user_15', password: 'my super password' }
622 const channel = { name: 'my_user_15_channel', displayName: 'my channel rocks' }
623
624 await registerUserWithChannel({ url: server.url, user, channel })
621 }) 625 })
622 626
623 it('Should be able to login with this registered user', async function () { 627 it('Should be able to login with this registered user', async function () {
@@ -636,6 +640,12 @@ describe('Test users', function () {
636 expect(user.videoQuota).to.equal(5 * 1024 * 1024) 640 expect(user.videoQuota).to.equal(5 * 1024 * 1024)
637 }) 641 })
638 642
643 it('Should have created the channel', async function () {
644 const res = await getVideoChannel(server.url, 'my_user_15_channel')
645
646 expect(res.body.displayName).to.equal('my channel rocks')
647 })
648
639 it('Should remove me', async function () { 649 it('Should remove me', async function () {
640 { 650 {
641 const res = await getUsersList(server.url, server.accessToken) 651 const res = await getUsersList(server.url, server.accessToken)
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts
index 68c1e9a8d..e9625e5f7 100644
--- a/server/tests/api/videos/multiple-servers.ts
+++ b/server/tests/api/videos/multiple-servers.ts
@@ -9,18 +9,17 @@ import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/
9import { 9import {
10 addVideoChannel, 10 addVideoChannel,
11 checkTmpIsEmpty, 11 checkTmpIsEmpty,
12 checkVideoFilesWereRemoved, cleanupTests, 12 checkVideoFilesWereRemoved,
13 cleanupTests,
13 completeVideoCheck, 14 completeVideoCheck,
14 createUser, 15 createUser,
15 dateIsValid, 16 dateIsValid,
16 doubleFollow, 17 doubleFollow,
17 flushAndRunMultipleServers, 18 flushAndRunMultipleServers,
18 flushTests,
19 getLocalVideos, 19 getLocalVideos,
20 getVideo, 20 getVideo,
21 getVideoChannelsList, 21 getVideoChannelsList,
22 getVideosList, 22 getVideosList,
23 killallServers,
24 rateVideo, 23 rateVideo,
25 removeVideo, 24 removeVideo,
26 ServerInfo, 25 ServerInfo,
@@ -110,7 +109,7 @@ describe('Test multiple servers', function () {
110 // All servers should have this video 109 // All servers should have this video
111 let publishedAt: string = null 110 let publishedAt: string = null
112 for (const server of servers) { 111 for (const server of servers) {
113 const isLocal = server.url === 'http://localhost:9001' 112 const isLocal = server.port === servers[0].port
114 const checkAttributes = { 113 const checkAttributes = {
115 name: 'my super name for server 1', 114 name: 'my super name for server 1',
116 category: 5, 115 category: 5,
@@ -122,7 +121,7 @@ describe('Test multiple servers', function () {
122 originallyPublishedAt: '2019-02-10T13:38:14.449Z', 121 originallyPublishedAt: '2019-02-10T13:38:14.449Z',
123 account: { 122 account: {
124 name: 'root', 123 name: 'root',
125 host: 'localhost:9001' 124 host: 'localhost:' + servers[0].port
126 }, 125 },
127 isLocal, 126 isLocal,
128 publishedAt, 127 publishedAt,
@@ -187,7 +186,7 @@ describe('Test multiple servers', function () {
187 186
188 // All servers should have this video 187 // All servers should have this video
189 for (const server of servers) { 188 for (const server of servers) {
190 const isLocal = server.url === 'http://localhost:9002' 189 const isLocal = server.url === 'http://localhost:' + servers[1].port
191 const checkAttributes = { 190 const checkAttributes = {
192 name: 'my super name for server 2', 191 name: 'my super name for server 2',
193 category: 4, 192 category: 4,
@@ -198,7 +197,7 @@ describe('Test multiple servers', function () {
198 support: 'my super support text for server 2', 197 support: 'my super support text for server 2',
199 account: { 198 account: {
200 name: 'user1', 199 name: 'user1',
201 host: 'localhost:9002' 200 host: 'localhost:' + servers[1].port
202 }, 201 },
203 isLocal, 202 isLocal,
204 commentsEnabled: true, 203 commentsEnabled: true,
@@ -216,7 +215,7 @@ describe('Test multiple servers', function () {
216 files: [ 215 files: [
217 { 216 {
218 resolution: 240, 217 resolution: 240,
219 size: 187000 218 size: 189000
220 }, 219 },
221 { 220 {
222 resolution: 360, 221 resolution: 360,
@@ -224,7 +223,7 @@ describe('Test multiple servers', function () {
224 }, 223 },
225 { 224 {
226 resolution: 480, 225 resolution: 480,
227 size: 383000 226 size: 384000
228 }, 227 },
229 { 228 {
230 resolution: 720, 229 resolution: 720,
@@ -278,7 +277,7 @@ describe('Test multiple servers', function () {
278 277
279 // All servers should have this video 278 // All servers should have this video
280 for (const server of servers) { 279 for (const server of servers) {
281 const isLocal = server.url === 'http://localhost:9003' 280 const isLocal = server.url === 'http://localhost:' + servers[2].port
282 const res = await getVideosList(server.url) 281 const res = await getVideosList(server.url)
283 282
284 const videos = res.body.data 283 const videos = res.body.data
@@ -306,7 +305,7 @@ describe('Test multiple servers', function () {
306 support: 'my super support text for server 3', 305 support: 'my super support text for server 3',
307 account: { 306 account: {
308 name: 'root', 307 name: 'root',
309 host: 'localhost:9003' 308 host: 'localhost:' + servers[2].port
310 }, 309 },
311 isLocal, 310 isLocal,
312 duration: 5, 311 duration: 5,
@@ -340,7 +339,7 @@ describe('Test multiple servers', function () {
340 support: 'my super support text for server 3-2', 339 support: 'my super support text for server 3-2',
341 account: { 340 account: {
342 name: 'root', 341 name: 'root',
343 host: 'localhost:9003' 342 host: 'localhost:' + servers[2].port
344 }, 343 },
345 commentsEnabled: true, 344 commentsEnabled: true,
346 downloadEnabled: true, 345 downloadEnabled: true,
@@ -646,7 +645,7 @@ describe('Test multiple servers', function () {
646 const videoUpdated = videos.find(video => video.name === 'my super video updated') 645 const videoUpdated = videos.find(video => video.name === 'my super video updated')
647 expect(!!videoUpdated).to.be.true 646 expect(!!videoUpdated).to.be.true
648 647
649 const isLocal = server.url === 'http://localhost:9003' 648 const isLocal = server.url === 'http://localhost:' + servers[2].port
650 const checkAttributes = { 649 const checkAttributes = {
651 name: 'my super video updated', 650 name: 'my super video updated',
652 category: 10, 651 category: 10,
@@ -658,7 +657,7 @@ describe('Test multiple servers', function () {
658 originallyPublishedAt: '2019-02-11T13:38:14.449Z', 657 originallyPublishedAt: '2019-02-11T13:38:14.449Z',
659 account: { 658 account: {
660 name: 'root', 659 name: 'root',
661 host: 'localhost:9003' 660 host: 'localhost:' + servers[2].port
662 }, 661 },
663 isLocal, 662 isLocal,
664 duration: 5, 663 duration: 5,
@@ -813,7 +812,7 @@ describe('Test multiple servers', function () {
813 expect(comment).to.not.be.undefined 812 expect(comment).to.not.be.undefined
814 expect(comment.inReplyToCommentId).to.be.null 813 expect(comment.inReplyToCommentId).to.be.null
815 expect(comment.account.name).to.equal('root') 814 expect(comment.account.name).to.equal('root')
816 expect(comment.account.host).to.equal('localhost:9001') 815 expect(comment.account.host).to.equal('localhost:' + servers[0].port)
817 expect(comment.totalReplies).to.equal(3) 816 expect(comment.totalReplies).to.equal(3)
818 expect(dateIsValid(comment.createdAt as string)).to.be.true 817 expect(dateIsValid(comment.createdAt as string)).to.be.true
819 expect(dateIsValid(comment.updatedAt as string)).to.be.true 818 expect(dateIsValid(comment.updatedAt as string)).to.be.true
@@ -824,7 +823,7 @@ describe('Test multiple servers', function () {
824 expect(comment).to.not.be.undefined 823 expect(comment).to.not.be.undefined
825 expect(comment.inReplyToCommentId).to.be.null 824 expect(comment.inReplyToCommentId).to.be.null
826 expect(comment.account.name).to.equal('root') 825 expect(comment.account.name).to.equal('root')
827 expect(comment.account.host).to.equal('localhost:9003') 826 expect(comment.account.host).to.equal('localhost:' + servers[2].port)
828 expect(comment.totalReplies).to.equal(0) 827 expect(comment.totalReplies).to.equal(0)
829 expect(dateIsValid(comment.createdAt as string)).to.be.true 828 expect(dateIsValid(comment.createdAt as string)).to.be.true
830 expect(dateIsValid(comment.updatedAt as string)).to.be.true 829 expect(dateIsValid(comment.updatedAt as string)).to.be.true
@@ -842,25 +841,25 @@ describe('Test multiple servers', function () {
842 const tree: VideoCommentThreadTree = res2.body 841 const tree: VideoCommentThreadTree = res2.body
843 expect(tree.comment.text).equal('my super first comment') 842 expect(tree.comment.text).equal('my super first comment')
844 expect(tree.comment.account.name).equal('root') 843 expect(tree.comment.account.name).equal('root')
845 expect(tree.comment.account.host).equal('localhost:9001') 844 expect(tree.comment.account.host).equal('localhost:' + servers[0].port)
846 expect(tree.children).to.have.lengthOf(2) 845 expect(tree.children).to.have.lengthOf(2)
847 846
848 const firstChild = tree.children[0] 847 const firstChild = tree.children[0]
849 expect(firstChild.comment.text).to.equal('my super answer to thread 1') 848 expect(firstChild.comment.text).to.equal('my super answer to thread 1')
850 expect(firstChild.comment.account.name).equal('root') 849 expect(firstChild.comment.account.name).equal('root')
851 expect(firstChild.comment.account.host).equal('localhost:9002') 850 expect(firstChild.comment.account.host).equal('localhost:' + servers[1].port)
852 expect(firstChild.children).to.have.lengthOf(1) 851 expect(firstChild.children).to.have.lengthOf(1)
853 852
854 childOfFirstChild = firstChild.children[0] 853 childOfFirstChild = firstChild.children[0]
855 expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') 854 expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1')
856 expect(childOfFirstChild.comment.account.name).equal('root') 855 expect(childOfFirstChild.comment.account.name).equal('root')
857 expect(childOfFirstChild.comment.account.host).equal('localhost:9003') 856 expect(childOfFirstChild.comment.account.host).equal('localhost:' + servers[2].port)
858 expect(childOfFirstChild.children).to.have.lengthOf(0) 857 expect(childOfFirstChild.children).to.have.lengthOf(0)
859 858
860 const secondChild = tree.children[1] 859 const secondChild = tree.children[1]
861 expect(secondChild.comment.text).to.equal('my second answer to thread 1') 860 expect(secondChild.comment.text).to.equal('my second answer to thread 1')
862 expect(secondChild.comment.account.name).equal('root') 861 expect(secondChild.comment.account.name).equal('root')
863 expect(secondChild.comment.account.host).equal('localhost:9003') 862 expect(secondChild.comment.account.host).equal('localhost:' + servers[2].port)
864 expect(secondChild.children).to.have.lengthOf(0) 863 expect(secondChild.children).to.have.lengthOf(0)
865 } 864 }
866 }) 865 })
@@ -915,7 +914,7 @@ describe('Test multiple servers', function () {
915 expect(comment).to.not.be.undefined 914 expect(comment).to.not.be.undefined
916 expect(comment.inReplyToCommentId).to.be.null 915 expect(comment.inReplyToCommentId).to.be.null
917 expect(comment.account.name).to.equal('root') 916 expect(comment.account.name).to.equal('root')
918 expect(comment.account.host).to.equal('localhost:9003') 917 expect(comment.account.host).to.equal('localhost:' + servers[2].port)
919 expect(comment.totalReplies).to.equal(0) 918 expect(comment.totalReplies).to.equal(0)
920 expect(dateIsValid(comment.createdAt as string)).to.be.true 919 expect(dateIsValid(comment.createdAt as string)).to.be.true
921 expect(dateIsValid(comment.updatedAt as string)).to.be.true 920 expect(dateIsValid(comment.updatedAt as string)).to.be.true
@@ -971,7 +970,7 @@ describe('Test multiple servers', function () {
971 const res = await getVideosList(server.url) 970 const res = await getVideosList(server.url)
972 const video = res.body.data.find(v => v.name === 'minimum parameters') 971 const video = res.body.data.find(v => v.name === 'minimum parameters')
973 972
974 const isLocal = server.url === 'http://localhost:9002' 973 const isLocal = server.url === 'http://localhost:' + servers[1].port
975 const checkAttributes = { 974 const checkAttributes = {
976 name: 'minimum parameters', 975 name: 'minimum parameters',
977 category: null, 976 category: null,
@@ -982,7 +981,7 @@ describe('Test multiple servers', function () {
982 support: null, 981 support: null,
983 account: { 982 account: {
984 name: 'root', 983 name: 'root',
985 host: 'localhost:9002' 984 host: 'localhost:' + servers[1].port
986 }, 985 },
987 isLocal, 986 isLocal,
988 duration: 5, 987 duration: 5,
diff --git a/server/tests/api/videos/services.ts b/server/tests/api/videos/services.ts
index e9ad947b2..17172331f 100644
--- a/server/tests/api/videos/services.ts
+++ b/server/tests/api/videos/services.ts
@@ -27,13 +27,13 @@ describe('Test services', function () {
27 }) 27 })
28 28
29 it('Should have a valid oEmbed response', async function () { 29 it('Should have a valid oEmbed response', async function () {
30 const oembedUrl = 'http://localhost:9001/videos/watch/' + server.video.uuid 30 const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + server.video.uuid
31 31
32 const res = await getOEmbed(server.url, oembedUrl) 32 const res = await getOEmbed(server.url, oembedUrl)
33 const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + 33 const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' +
34 `src="http://localhost:9001/videos/embed/${server.video.uuid}" ` + 34 `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` +
35 'frameborder="0" allowfullscreen></iframe>' 35 'frameborder="0" allowfullscreen></iframe>'
36 const expectedThumbnailUrl = 'http://localhost:9001/static/previews/' + server.video.uuid + '.jpg' 36 const expectedThumbnailUrl = 'http://localhost:' + server.port + '/static/previews/' + server.video.uuid + '.jpg'
37 37
38 expect(res.body.html).to.equal(expectedHtml) 38 expect(res.body.html).to.equal(expectedHtml)
39 expect(res.body.title).to.equal(server.video.name) 39 expect(res.body.title).to.equal(server.video.name)
@@ -41,19 +41,19 @@ describe('Test services', function () {
41 expect(res.body.width).to.equal(560) 41 expect(res.body.width).to.equal(560)
42 expect(res.body.height).to.equal(315) 42 expect(res.body.height).to.equal(315)
43 expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl) 43 expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl)
44 expect(res.body.thumbnail_width).to.equal(560) 44 expect(res.body.thumbnail_width).to.equal(850)
45 expect(res.body.thumbnail_height).to.equal(315) 45 expect(res.body.thumbnail_height).to.equal(480)
46 }) 46 })
47 47
48 it('Should have a valid oEmbed response with small max height query', async function () { 48 it('Should have a valid oEmbed response with small max height query', async function () {
49 const oembedUrl = 'http://localhost:9001/videos/watch/' + server.video.uuid 49 const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + server.video.uuid
50 const format = 'json' 50 const format = 'json'
51 const maxHeight = 50 51 const maxHeight = 50
52 const maxWidth = 50 52 const maxWidth = 50
53 53
54 const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth) 54 const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth)
55 const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' + 55 const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' +
56 `src="http://localhost:9001/videos/embed/${server.video.uuid}" ` + 56 `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` +
57 'frameborder="0" allowfullscreen></iframe>' 57 'frameborder="0" allowfullscreen></iframe>'
58 58
59 expect(res.body.html).to.equal(expectedHtml) 59 expect(res.body.html).to.equal(expectedHtml)
diff --git a/server/tests/api/videos/single-server.ts b/server/tests/api/videos/single-server.ts
index 1f366b642..d8f394ac7 100644
--- a/server/tests/api/videos/single-server.ts
+++ b/server/tests/api/videos/single-server.ts
@@ -37,7 +37,7 @@ describe('Test a single server', function () {
37 let videoUUID = '' 37 let videoUUID = ''
38 let videosListBase: any[] = null 38 let videosListBase: any[] = null
39 39
40 const getCheckAttributes = { 40 const getCheckAttributes = () => ({
41 name: 'my super name', 41 name: 'my super name',
42 category: 2, 42 category: 2,
43 licence: 6, 43 licence: 6,
@@ -47,7 +47,7 @@ describe('Test a single server', function () {
47 support: 'my super support text', 47 support: 'my super support text',
48 account: { 48 account: {
49 name: 'root', 49 name: 'root',
50 host: 'localhost:9001' 50 host: 'localhost:' + server.port
51 }, 51 },
52 isLocal: true, 52 isLocal: true,
53 duration: 5, 53 duration: 5,
@@ -68,9 +68,9 @@ describe('Test a single server', function () {
68 size: 218910 68 size: 218910
69 } 69 }
70 ] 70 ]
71 } 71 })
72 72
73 const updateCheckAttributes = { 73 const updateCheckAttributes = () => ({
74 name: 'my super video updated', 74 name: 'my super video updated',
75 category: 4, 75 category: 4,
76 licence: 2, 76 licence: 2,
@@ -80,7 +80,7 @@ describe('Test a single server', function () {
80 support: 'my super support text updated', 80 support: 'my super support text updated',
81 account: { 81 account: {
82 name: 'root', 82 name: 'root',
83 host: 'localhost:9001' 83 host: 'localhost:' + server.port
84 }, 84 },
85 isLocal: true, 85 isLocal: true,
86 tags: [ 'tagup1', 'tagup2' ], 86 tags: [ 'tagup1', 'tagup2' ],
@@ -101,7 +101,7 @@ describe('Test a single server', function () {
101 size: 292677 101 size: 292677
102 } 102 }
103 ] 103 ]
104 } 104 })
105 105
106 before(async function () { 106 before(async function () {
107 this.timeout(30000) 107 this.timeout(30000)
@@ -182,7 +182,7 @@ describe('Test a single server', function () {
182 expect(res.body.data.length).to.equal(1) 182 expect(res.body.data.length).to.equal(1)
183 183
184 const video = res.body.data[0] 184 const video = res.body.data[0]
185 await completeVideoCheck(server.url, video, getCheckAttributes) 185 await completeVideoCheck(server.url, video, getCheckAttributes())
186 }) 186 })
187 187
188 it('Should get the video by UUID', async function () { 188 it('Should get the video by UUID', async function () {
@@ -191,7 +191,7 @@ describe('Test a single server', function () {
191 const res = await getVideo(server.url, videoUUID) 191 const res = await getVideo(server.url, videoUUID)
192 192
193 const video = res.body 193 const video = res.body
194 await completeVideoCheck(server.url, video, getCheckAttributes) 194 await completeVideoCheck(server.url, video, getCheckAttributes())
195 }) 195 })
196 196
197 it('Should have the views updated', async function () { 197 it('Should have the views updated', async function () {
@@ -376,7 +376,7 @@ describe('Test a single server', function () {
376 const res = await getVideo(server.url, videoId) 376 const res = await getVideo(server.url, videoId)
377 const video = res.body 377 const video = res.body
378 378
379 await completeVideoCheck(server.url, video, updateCheckAttributes) 379 await completeVideoCheck(server.url, video, updateCheckAttributes())
380 }) 380 })
381 381
382 it('Should update only the tags of a video', async function () { 382 it('Should update only the tags of a video', async function () {
@@ -388,7 +388,7 @@ describe('Test a single server', function () {
388 const res = await getVideo(server.url, videoId) 388 const res = await getVideo(server.url, videoId)
389 const video = res.body 389 const video = res.body
390 390
391 await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes, attributes)) 391 await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes(), attributes))
392 }) 392 })
393 393
394 it('Should update only the description of a video', async function () { 394 it('Should update only the description of a video', async function () {
@@ -400,7 +400,8 @@ describe('Test a single server', function () {
400 const res = await getVideo(server.url, videoId) 400 const res = await getVideo(server.url, videoId)
401 const video = res.body 401 const video = res.body
402 402
403 await completeVideoCheck(server.url, video, Object.assign(updateCheckAttributes, attributes)) 403 const expectedAttributes = Object.assign(updateCheckAttributes(), { tags: [ 'supertag', 'tag1', 'tag2' ] }, attributes)
404 await completeVideoCheck(server.url, video, expectedAttributes)
404 }) 405 })
405 406
406 it('Should like a video', async function () { 407 it('Should like a video', async function () {
diff --git a/server/tests/api/videos/video-abuse.ts b/server/tests/api/videos/video-abuse.ts
index 7318497d5..a2f3ee161 100644
--- a/server/tests/api/videos/video-abuse.ts
+++ b/server/tests/api/videos/video-abuse.ts
@@ -9,7 +9,6 @@ import {
9 flushAndRunMultipleServers, 9 flushAndRunMultipleServers,
10 getVideoAbusesList, 10 getVideoAbusesList,
11 getVideosList, 11 getVideosList,
12 killallServers,
13 reportVideoAbuse, 12 reportVideoAbuse,
14 ServerInfo, 13 ServerInfo,
15 setAccessTokensToServers, 14 setAccessTokensToServers,
@@ -90,7 +89,7 @@ describe('Test video abuses', function () {
90 const abuse: VideoAbuse = res1.body.data[0] 89 const abuse: VideoAbuse = res1.body.data[0]
91 expect(abuse.reason).to.equal('my super bad reason') 90 expect(abuse.reason).to.equal('my super bad reason')
92 expect(abuse.reporterAccount.name).to.equal('root') 91 expect(abuse.reporterAccount.name).to.equal('root')
93 expect(abuse.reporterAccount.host).to.equal('localhost:9001') 92 expect(abuse.reporterAccount.host).to.equal('localhost:' + servers[0].port)
94 expect(abuse.video.id).to.equal(servers[0].video.id) 93 expect(abuse.video.id).to.equal(servers[0].video.id)
95 94
96 const res2 = await getVideoAbusesList(servers[1].url, servers[1].accessToken) 95 const res2 = await getVideoAbusesList(servers[1].url, servers[1].accessToken)
@@ -118,7 +117,7 @@ describe('Test video abuses', function () {
118 const abuse1: VideoAbuse = res1.body.data[0] 117 const abuse1: VideoAbuse = res1.body.data[0]
119 expect(abuse1.reason).to.equal('my super bad reason') 118 expect(abuse1.reason).to.equal('my super bad reason')
120 expect(abuse1.reporterAccount.name).to.equal('root') 119 expect(abuse1.reporterAccount.name).to.equal('root')
121 expect(abuse1.reporterAccount.host).to.equal('localhost:9001') 120 expect(abuse1.reporterAccount.host).to.equal('localhost:' + servers[0].port)
122 expect(abuse1.video.id).to.equal(servers[0].video.id) 121 expect(abuse1.video.id).to.equal(servers[0].video.id)
123 expect(abuse1.state.id).to.equal(VideoAbuseState.PENDING) 122 expect(abuse1.state.id).to.equal(VideoAbuseState.PENDING)
124 expect(abuse1.state.label).to.equal('Pending') 123 expect(abuse1.state.label).to.equal('Pending')
@@ -127,7 +126,7 @@ describe('Test video abuses', function () {
127 const abuse2: VideoAbuse = res1.body.data[1] 126 const abuse2: VideoAbuse = res1.body.data[1]
128 expect(abuse2.reason).to.equal('my super bad reason 2') 127 expect(abuse2.reason).to.equal('my super bad reason 2')
129 expect(abuse2.reporterAccount.name).to.equal('root') 128 expect(abuse2.reporterAccount.name).to.equal('root')
130 expect(abuse2.reporterAccount.host).to.equal('localhost:9001') 129 expect(abuse2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
131 expect(abuse2.video.id).to.equal(servers[1].video.id) 130 expect(abuse2.video.id).to.equal(servers[1].video.id)
132 expect(abuse2.state.id).to.equal(VideoAbuseState.PENDING) 131 expect(abuse2.state.id).to.equal(VideoAbuseState.PENDING)
133 expect(abuse2.state.label).to.equal('Pending') 132 expect(abuse2.state.label).to.equal('Pending')
@@ -141,7 +140,7 @@ describe('Test video abuses', function () {
141 abuseServer2 = res2.body.data[0] 140 abuseServer2 = res2.body.data[0]
142 expect(abuseServer2.reason).to.equal('my super bad reason 2') 141 expect(abuseServer2.reason).to.equal('my super bad reason 2')
143 expect(abuseServer2.reporterAccount.name).to.equal('root') 142 expect(abuseServer2.reporterAccount.name).to.equal('root')
144 expect(abuseServer2.reporterAccount.host).to.equal('localhost:9001') 143 expect(abuseServer2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
145 expect(abuseServer2.state.id).to.equal(VideoAbuseState.PENDING) 144 expect(abuseServer2.state.id).to.equal(VideoAbuseState.PENDING)
146 expect(abuseServer2.state.label).to.equal('Pending') 145 expect(abuseServer2.state.label).to.equal('Pending')
147 expect(abuseServer2.moderationComment).to.be.null 146 expect(abuseServer2.moderationComment).to.be.null
diff --git a/server/tests/api/videos/video-change-ownership.ts b/server/tests/api/videos/video-change-ownership.ts
index 1c0327d40..3a3add71b 100644
--- a/server/tests/api/videos/video-change-ownership.ts
+++ b/server/tests/api/videos/video-change-ownership.ts
@@ -4,7 +4,8 @@ import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { 5import {
6 acceptChangeOwnership, 6 acceptChangeOwnership,
7 changeVideoOwnership, cleanupTests, 7 changeVideoOwnership,
8 cleanupTests,
8 createUser, 9 createUser,
9 doubleFollow, 10 doubleFollow,
10 flushAndRunMultipleServers, 11 flushAndRunMultipleServers,
@@ -13,7 +14,6 @@ import {
13 getVideo, 14 getVideo,
14 getVideoChangeOwnershipList, 15 getVideoChangeOwnershipList,
15 getVideosList, 16 getVideosList,
16 killallServers,
17 refuseChangeOwnership, 17 refuseChangeOwnership,
18 ServerInfo, 18 ServerInfo,
19 setAccessTokensToServers, 19 setAccessTokensToServers,
@@ -203,8 +203,8 @@ describe('Test video change ownership - nominal', function () {
203 } 203 }
204 }) 204 })
205 205
206 after(function () { 206 after(async function () {
207 killallServers(servers) 207 await cleanupTests(servers)
208 }) 208 })
209}) 209})
210 210
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts
index 345e96f43..4f600cae8 100644
--- a/server/tests/api/videos/video-channels.ts
+++ b/server/tests/api/videos/video-channels.ts
@@ -2,12 +2,12 @@
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { User, Video } from '../../../../shared/index' 5import { User, Video, VideoChannel, VideoDetails } from '../../../../shared/index'
6import { 6import {
7 cleanupTests, 7 cleanupTests,
8 createUser, 8 createUser,
9 doubleFollow, 9 doubleFollow,
10 flushAndRunMultipleServers, 10 flushAndRunMultipleServers, getVideo,
11 getVideoChannelVideos, 11 getVideoChannelVideos,
12 testImage, 12 testImage,
13 updateVideo, 13 updateVideo,
@@ -18,12 +18,10 @@ import {
18import { 18import {
19 addVideoChannel, 19 addVideoChannel,
20 deleteVideoChannel, 20 deleteVideoChannel,
21 flushTests,
22 getAccountVideoChannelsList, 21 getAccountVideoChannelsList,
23 getMyUserInformation, 22 getMyUserInformation,
24 getVideoChannel, 23 getVideoChannel,
25 getVideoChannelsList, 24 getVideoChannelsList,
26 killallServers,
27 ServerInfo, 25 ServerInfo,
28 setAccessTokensToServers, 26 setAccessTokensToServers,
29 updateVideoChannel 27 updateVideoChannel
@@ -35,13 +33,12 @@ const expect = chai.expect
35describe('Test video channels', function () { 33describe('Test video channels', function () {
36 let servers: ServerInfo[] 34 let servers: ServerInfo[]
37 let userInfo: User 35 let userInfo: User
38 let accountUUID: string
39 let firstVideoChannelId: number 36 let firstVideoChannelId: number
40 let secondVideoChannelId: number 37 let secondVideoChannelId: number
41 let videoUUID: string 38 let videoUUID: string
42 39
43 before(async function () { 40 before(async function () {
44 this.timeout(30000) 41 this.timeout(60000)
45 42
46 servers = await flushAndRunMultipleServers(2) 43 servers = await flushAndRunMultipleServers(2)
47 44
@@ -51,7 +48,6 @@ describe('Test video channels', function () {
51 { 48 {
52 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) 49 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
53 const user: User = res.body 50 const user: User = res.body
54 accountUUID = user.account.uuid
55 51
56 firstVideoChannelId = user.videoChannels[0].id 52 firstVideoChannelId = user.videoChannels[0].id
57 } 53 }
@@ -83,7 +79,8 @@ describe('Test video channels', function () {
83 79
84 // The channel is 1 is propagated to servers 2 80 // The channel is 1 is propagated to servers 2
85 { 81 {
86 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'my video name', channelId: secondVideoChannelId }) 82 const videoAttributesArg = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' }
83 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributesArg)
87 videoUUID = res.body.video.uuid 84 videoUUID = res.body.video.uuid
88 } 85 }
89 86
@@ -108,7 +105,11 @@ describe('Test video channels', function () {
108 }) 105 })
109 106
110 it('Should have two video channels when getting account channels on server 1', async function () { 107 it('Should have two video channels when getting account channels on server 1', async function () {
111 const res = await getAccountVideoChannelsList(servers[0].url, userInfo.account.name + '@' + userInfo.account.host) 108 const res = await getAccountVideoChannelsList({
109 url: servers[ 0 ].url,
110 accountName: userInfo.account.name + '@' + userInfo.account.host
111 })
112
112 expect(res.body.total).to.equal(2) 113 expect(res.body.total).to.equal(2)
113 expect(res.body.data).to.be.an('array') 114 expect(res.body.data).to.be.an('array')
114 expect(res.body.data).to.have.lengthOf(2) 115 expect(res.body.data).to.have.lengthOf(2)
@@ -123,8 +124,62 @@ describe('Test video channels', function () {
123 expect(videoChannels[1].support).to.equal('super video channel support text') 124 expect(videoChannels[1].support).to.equal('super video channel support text')
124 }) 125 })
125 126
127 it('Should paginate and sort account channels', async function () {
128 {
129 const res = await getAccountVideoChannelsList({
130 url: servers[ 0 ].url,
131 accountName: userInfo.account.name + '@' + userInfo.account.host,
132 start: 0,
133 count: 1,
134 sort: 'createdAt'
135 })
136
137 expect(res.body.total).to.equal(2)
138 expect(res.body.data).to.have.lengthOf(1)
139
140 const videoChannel: VideoChannel = res.body.data[ 0 ]
141 expect(videoChannel.name).to.equal('root_channel')
142 }
143
144 {
145 const res = await getAccountVideoChannelsList({
146 url: servers[ 0 ].url,
147 accountName: userInfo.account.name + '@' + userInfo.account.host,
148 start: 0,
149 count: 1,
150 sort: '-createdAt'
151 })
152
153 expect(res.body.total).to.equal(2)
154 expect(res.body.data).to.have.lengthOf(1)
155
156 const videoChannel: VideoChannel = res.body.data[ 0 ]
157 expect(videoChannel.name).to.equal('second_video_channel')
158 }
159
160 {
161 const res = await getAccountVideoChannelsList({
162 url: servers[ 0 ].url,
163 accountName: userInfo.account.name + '@' + userInfo.account.host,
164 start: 1,
165 count: 1,
166 sort: '-createdAt'
167 })
168
169 expect(res.body.total).to.equal(2)
170 expect(res.body.data).to.have.lengthOf(1)
171
172 const videoChannel: VideoChannel = res.body.data[ 0 ]
173 expect(videoChannel.name).to.equal('root_channel')
174 }
175 })
176
126 it('Should have one video channel when getting account channels on server 2', async function () { 177 it('Should have one video channel when getting account channels on server 2', async function () {
127 const res = await getAccountVideoChannelsList(servers[1].url, userInfo.account.name + '@' + userInfo.account.host) 178 const res = await getAccountVideoChannelsList({
179 url: servers[ 1 ].url,
180 accountName: userInfo.account.name + '@' + userInfo.account.host
181 })
182
128 expect(res.body.total).to.equal(1) 183 expect(res.body.total).to.equal(1)
129 expect(res.body.data).to.be.an('array') 184 expect(res.body.data).to.be.an('array')
130 expect(res.body.data).to.have.lengthOf(1) 185 expect(res.body.data).to.have.lengthOf(1)
@@ -147,12 +202,12 @@ describe('Test video channels', function () {
147 }) 202 })
148 203
149 it('Should update video channel', async function () { 204 it('Should update video channel', async function () {
150 this.timeout(5000) 205 this.timeout(15000)
151 206
152 const videoChannelAttributes = { 207 const videoChannelAttributes = {
153 displayName: 'video channel updated', 208 displayName: 'video channel updated',
154 description: 'video channel description updated', 209 description: 'video channel description updated',
155 support: 'video channel support text updated' 210 support: 'support updated'
156 } 211 }
157 212
158 await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes) 213 await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes)
@@ -170,7 +225,36 @@ describe('Test video channels', function () {
170 expect(res.body.data[0].name).to.equal('second_video_channel') 225 expect(res.body.data[0].name).to.equal('second_video_channel')
171 expect(res.body.data[0].displayName).to.equal('video channel updated') 226 expect(res.body.data[0].displayName).to.equal('video channel updated')
172 expect(res.body.data[0].description).to.equal('video channel description updated') 227 expect(res.body.data[0].description).to.equal('video channel description updated')
173 expect(res.body.data[0].support).to.equal('video channel support text updated') 228 expect(res.body.data[0].support).to.equal('support updated')
229 }
230 })
231
232 it('Should not have updated the video support field', async function () {
233 for (const server of servers) {
234 const res = await getVideo(server.url, videoUUID)
235 const video: VideoDetails = res.body
236
237 expect(video.support).to.equal('video support field')
238 }
239 })
240
241 it('Should update the channel support field and update videos too', async function () {
242 this.timeout(35000)
243
244 const videoChannelAttributes = {
245 support: 'video channel support text updated',
246 bulkVideosSupportUpdate: true
247 }
248
249 await updateVideoChannel(servers[0].url, servers[0].accessToken, 'second_video_channel', videoChannelAttributes)
250
251 await waitJobs(servers)
252
253 for (const server of servers) {
254 const res = await getVideo(server.url, videoUUID)
255 const video: VideoDetails = res.body
256
257 expect(video.support).to.equal(videoChannelAttributes.support)
174 } 258 }
175 }) 259 })
176 260
@@ -213,7 +297,7 @@ describe('Test video channels', function () {
213 this.timeout(10000) 297 this.timeout(10000)
214 298
215 for (const server of servers) { 299 for (const server of servers) {
216 const channelURI = 'second_video_channel@localhost:9001' 300 const channelURI = 'second_video_channel@localhost:' + servers[0].port
217 const res1 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5) 301 const res1 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5)
218 expect(res1.body.total).to.equal(1) 302 expect(res1.body.total).to.equal(1)
219 expect(res1.body.data).to.be.an('array') 303 expect(res1.body.data).to.be.an('array')
@@ -234,11 +318,11 @@ describe('Test video channels', function () {
234 this.timeout(10000) 318 this.timeout(10000)
235 319
236 for (const server of servers) { 320 for (const server of servers) {
237 const secondChannelURI = 'second_video_channel@localhost:9001' 321 const secondChannelURI = 'second_video_channel@localhost:' + servers[0].port
238 const res1 = await getVideoChannelVideos(server.url, server.accessToken, secondChannelURI, 0, 5) 322 const res1 = await getVideoChannelVideos(server.url, server.accessToken, secondChannelURI, 0, 5)
239 expect(res1.body.total).to.equal(0) 323 expect(res1.body.total).to.equal(0)
240 324
241 const channelURI = 'root_channel@localhost:9001' 325 const channelURI = 'root_channel@localhost:' + servers[0].port
242 const res2 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5) 326 const res2 = await getVideoChannelVideos(server.url, server.accessToken, channelURI, 0, 5)
243 expect(res2.body.total).to.equal(1) 327 expect(res2.body.total).to.equal(1)
244 328
diff --git a/server/tests/api/videos/video-comments.ts b/server/tests/api/videos/video-comments.ts
index 22fd8c058..82182cc7c 100644
--- a/server/tests/api/videos/video-comments.ts
+++ b/server/tests/api/videos/video-comments.ts
@@ -66,8 +66,8 @@ describe('Test video comments', function () {
66 expect(comment.videoId).to.equal(videoId) 66 expect(comment.videoId).to.equal(videoId)
67 expect(comment.id).to.equal(comment.threadId) 67 expect(comment.id).to.equal(comment.threadId)
68 expect(comment.account.name).to.equal('root') 68 expect(comment.account.name).to.equal('root')
69 expect(comment.account.host).to.equal('localhost:9001') 69 expect(comment.account.host).to.equal('localhost:' + server.port)
70 expect(comment.account.url).to.equal('http://localhost:9001/accounts/root') 70 expect(comment.account.url).to.equal('http://localhost:' + server.port + '/accounts/root')
71 expect(comment.totalReplies).to.equal(0) 71 expect(comment.totalReplies).to.equal(0)
72 expect(dateIsValid(comment.createdAt as string)).to.be.true 72 expect(dateIsValid(comment.createdAt as string)).to.be.true
73 expect(dateIsValid(comment.updatedAt as string)).to.be.true 73 expect(dateIsValid(comment.updatedAt as string)).to.be.true
@@ -86,7 +86,7 @@ describe('Test video comments', function () {
86 expect(comment.videoId).to.equal(videoId) 86 expect(comment.videoId).to.equal(videoId)
87 expect(comment.id).to.equal(comment.threadId) 87 expect(comment.id).to.equal(comment.threadId)
88 expect(comment.account.name).to.equal('root') 88 expect(comment.account.name).to.equal('root')
89 expect(comment.account.host).to.equal('localhost:9001') 89 expect(comment.account.host).to.equal('localhost:' + server.port)
90 90
91 await testImage(server.url, 'avatar-resized', comment.account.avatar.path, '.png') 91 await testImage(server.url, 'avatar-resized', comment.account.avatar.path, '.png')
92 92
diff --git a/server/tests/api/videos/video-hls.ts b/server/tests/api/videos/video-hls.ts
index 22031c18b..39178bb1a 100644
--- a/server/tests/api/videos/video-hls.ts
+++ b/server/tests/api/videos/video-hls.ts
@@ -5,13 +5,12 @@ import 'mocha'
5import { 5import {
6 checkDirectoryIsEmpty, 6 checkDirectoryIsEmpty,
7 checkSegmentHash, 7 checkSegmentHash,
8 checkTmpIsEmpty, cleanupTests, 8 checkTmpIsEmpty,
9 cleanupTests,
9 doubleFollow, 10 doubleFollow,
10 flushAndRunMultipleServers, 11 flushAndRunMultipleServers,
11 flushTests,
12 getPlaylist, 12 getPlaylist,
13 getVideo, 13 getVideo,
14 killallServers,
15 removeVideo, 14 removeVideo,
16 ServerInfo, 15 ServerInfo,
17 setAccessTokensToServers, 16 setAccessTokensToServers,
@@ -22,12 +21,11 @@ import {
22import { VideoDetails } from '../../../../shared/models/videos' 21import { VideoDetails } from '../../../../shared/models/videos'
23import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' 22import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type'
24import { join } from 'path' 23import { join } from 'path'
24import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants'
25 25
26const expect = chai.expect 26const expect = chai.expect
27 27
28async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string) { 28async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, resolutions = [ 240, 360, 480, 720 ]) {
29 const resolutions = [ 240, 360, 480, 720 ]
30
31 for (const server of servers) { 29 for (const server of servers) {
32 const res = await getVideo(server.url, videoUUID) 30 const res = await getVideo(server.url, videoUUID)
33 const videoDetails: VideoDetails = res.body 31 const videoDetails: VideoDetails = res.body
@@ -42,16 +40,15 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string) {
42 40
43 const masterPlaylist = res2.text 41 const masterPlaylist = res2.text
44 42
45 expect(masterPlaylist).to.contain('#EXT-X-STREAM-INF:BANDWIDTH=55472,RESOLUTION=640x360,FRAME-RATE=25')
46
47 for (const resolution of resolutions) { 43 for (const resolution of resolutions) {
44 expect(masterPlaylist).to.match(new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+'))
48 expect(masterPlaylist).to.contain(`${resolution}.m3u8`) 45 expect(masterPlaylist).to.contain(`${resolution}.m3u8`)
49 } 46 }
50 } 47 }
51 48
52 { 49 {
53 for (const resolution of resolutions) { 50 for (const resolution of resolutions) {
54 const res2 = await getPlaylist(`http://localhost:9001/static/streaming-playlists/hls/${videoUUID}/${resolution}.m3u8`) 51 const res2 = await getPlaylist(`http://localhost:${servers[0].port}/static/streaming-playlists/hls/${videoUUID}/${resolution}.m3u8`)
55 52
56 const subPlaylist = res2.text 53 const subPlaylist = res2.text
57 expect(subPlaylist).to.contain(`${videoUUID}-${resolution}-fragmented.mp4`) 54 expect(subPlaylist).to.contain(`${videoUUID}-${resolution}-fragmented.mp4`)
@@ -59,7 +56,7 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string) {
59 } 56 }
60 57
61 { 58 {
62 const baseUrl = 'http://localhost:9001/static/streaming-playlists/hls' 59 const baseUrl = 'http://localhost:' + servers[0].port + '/static/streaming-playlists/hls'
63 60
64 for (const resolution of resolutions) { 61 for (const resolution of resolutions) {
65 await checkSegmentHash(baseUrl, baseUrl, videoUUID, resolution, hlsPlaylist) 62 await checkSegmentHash(baseUrl, baseUrl, videoUUID, resolution, hlsPlaylist)
@@ -71,11 +68,21 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string) {
71describe('Test HLS videos', function () { 68describe('Test HLS videos', function () {
72 let servers: ServerInfo[] = [] 69 let servers: ServerInfo[] = []
73 let videoUUID = '' 70 let videoUUID = ''
71 let videoAudioUUID = ''
74 72
75 before(async function () { 73 before(async function () {
76 this.timeout(120000) 74 this.timeout(120000)
77 75
78 servers = await flushAndRunMultipleServers(2, { transcoding: { enabled: true, hls: { enabled: true } } }) 76 const configOverride = {
77 transcoding: {
78 enabled: true,
79 allow_audio_files: true,
80 hls: {
81 enabled: true
82 }
83 }
84 }
85 servers = await flushAndRunMultipleServers(2, configOverride)
79 86
80 // Get the access tokens 87 // Get the access tokens
81 await setAccessTokensToServers(servers) 88 await setAccessTokensToServers(servers)
@@ -87,17 +94,28 @@ describe('Test HLS videos', function () {
87 it('Should upload a video and transcode it to HLS', async function () { 94 it('Should upload a video and transcode it to HLS', async function () {
88 this.timeout(120000) 95 this.timeout(120000)
89 96
90 { 97 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' })
91 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' }) 98 videoUUID = res.body.video.uuid
92 videoUUID = res.body.video.uuid
93 }
94 99
95 await waitJobs(servers) 100 await waitJobs(servers)
96 101
97 await checkHlsPlaylist(servers, videoUUID) 102 await checkHlsPlaylist(servers, videoUUID)
98 }) 103 })
99 104
105 it('Should upload an audio file and transcode it to HLS', async function () {
106 this.timeout(120000)
107
108 const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video audio', fixture: 'sample.ogg' })
109 videoAudioUUID = res.body.video.uuid
110
111 await waitJobs(servers)
112
113 await checkHlsPlaylist(servers, videoAudioUUID, [ DEFAULT_AUDIO_RESOLUTION ])
114 })
115
100 it('Should update the video', async function () { 116 it('Should update the video', async function () {
117 this.timeout(10000)
118
101 await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video 1 updated' }) 119 await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video 1 updated' })
102 120
103 await waitJobs(servers) 121 await waitJobs(servers)
@@ -105,13 +123,17 @@ describe('Test HLS videos', function () {
105 await checkHlsPlaylist(servers, videoUUID) 123 await checkHlsPlaylist(servers, videoUUID)
106 }) 124 })
107 125
108 it('Should delete the video', async function () { 126 it('Should delete videos', async function () {
127 this.timeout(10000)
128
109 await removeVideo(servers[0].url, servers[0].accessToken, videoUUID) 129 await removeVideo(servers[0].url, servers[0].accessToken, videoUUID)
130 await removeVideo(servers[0].url, servers[0].accessToken, videoAudioUUID)
110 131
111 await waitJobs(servers) 132 await waitJobs(servers)
112 133
113 for (const server of servers) { 134 for (const server of servers) {
114 await getVideo(server.url, videoUUID, 404) 135 await getVideo(server.url, videoUUID, 404)
136 await getVideo(server.url, videoAudioUUID, 404)
115 } 137 }
116 }) 138 })
117 139
diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts
index fd5e4c4be..8690327c4 100644
--- a/server/tests/api/videos/video-playlists.ts
+++ b/server/tests/api/videos/video-playlists.ts
@@ -371,7 +371,7 @@ describe('Test video playlists', function () {
371 371
372 for (const server of servers) { 372 for (const server of servers) {
373 const results = [ 373 const results = [
374 await getAccountPlaylistsList(server.url, 'root@localhost:9002', 0, 5, '-createdAt'), 374 await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'),
375 await getVideoPlaylistsList(server.url, 0, 2, '-createdAt') 375 await getVideoPlaylistsList(server.url, 0, 2, '-createdAt')
376 ] 376 ]
377 377
@@ -754,6 +754,40 @@ describe('Test video playlists', function () {
754 } 754 }
755 }) 755 })
756 756
757
758 it('Should be able to create a public playlist, and set it to private', async function () {
759 this.timeout(30000)
760
761 const res = await createVideoPlaylist({
762 url: servers[0].url,
763 token: servers[0].accessToken,
764 playlistAttrs: {
765 displayName: 'my super public playlist',
766 privacy: VideoPlaylistPrivacy.PUBLIC,
767 videoChannelId: servers[0].videoChannel.id
768 }
769 })
770 const videoPlaylistIds = res.body.videoPlaylist
771
772 await waitJobs(servers)
773
774 for (const server of servers) {
775 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 200)
776 }
777
778 const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE }
779 await updateVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs })
780
781 await waitJobs(servers)
782
783 for (const server of [ servers[1], servers[2] ]) {
784 await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404)
785 }
786 await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, 401)
787
788 await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, 200)
789 })
790
757 it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () { 791 it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () {
758 this.timeout(30000) 792 this.timeout(30000)
759 793
@@ -770,7 +804,7 @@ describe('Test video playlists', function () {
770 this.timeout(30000) 804 this.timeout(30000)
771 805
772 for (const server of servers) { 806 for (const server of servers) {
773 await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.serverNumber) 807 await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.internalServerNumber)
774 } 808 }
775 }) 809 })
776 810
diff --git a/server/tests/api/videos/video-privacy.ts b/server/tests/api/videos/video-privacy.ts
index ef1cf0f07..40b539106 100644
--- a/server/tests/api/videos/video-privacy.ts
+++ b/server/tests/api/videos/video-privacy.ts
@@ -6,8 +6,7 @@ import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enu
6import { 6import {
7 cleanupTests, 7 cleanupTests,
8 flushAndRunMultipleServers, 8 flushAndRunMultipleServers,
9 getVideosList, 9 getVideosList, getVideosListWithToken,
10 killallServers,
11 ServerInfo, 10 ServerInfo,
12 setAccessTokensToServers, 11 setAccessTokensToServers,
13 uploadVideo 12 uploadVideo
@@ -153,6 +152,29 @@ describe('Test video privacy', function () {
153 } 152 }
154 }) 153 })
155 154
155 it('Should set this new video as private', async function () {
156 this.timeout(10000)
157
158 await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, { privacy: VideoPrivacy.PRIVATE })
159
160 await waitJobs(servers)
161
162 for (const server of servers) {
163 const res = await getVideosList(server.url)
164
165 expect(res.body.total).to.equal(0)
166 expect(res.body.data).to.have.lengthOf(0)
167 }
168
169 {
170 const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 5)
171
172 expect(res.body.total).to.equal(1)
173 expect(res.body.data).to.have.lengthOf(1)
174 expect(res.body.data[0].name).to.equal('super video public')
175 }
176 })
177
156 after(async function () { 178 after(async function () {
157 await cleanupTests(servers) 179 await cleanupTests(servers)
158 }) 180 })
diff --git a/server/tests/api/videos/video-transcoder.ts b/server/tests/api/videos/video-transcoder.ts
index 3cd43e99b..90ade1652 100644
--- a/server/tests/api/videos/video-transcoder.ts
+++ b/server/tests/api/videos/video-transcoder.ts
@@ -4,24 +4,25 @@ import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { omit } from 'lodash' 5import { omit } from 'lodash'
6import { getMaxBitrate, VideoDetails, VideoResolution, VideoState } from '../../../../shared/models/videos' 6import { getMaxBitrate, VideoDetails, VideoResolution, VideoState } from '../../../../shared/models/videos'
7import { audio, getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' 7import { audio, canDoQuickTranscode, getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
8import { 8import {
9 buildAbsoluteFixturePath, cleanupTests, 9 buildAbsoluteFixturePath,
10 cleanupTests,
10 doubleFollow, 11 doubleFollow,
11 flushAndRunMultipleServers, 12 flushAndRunMultipleServers,
12 generateHighBitrateVideo, 13 generateHighBitrateVideo,
13 getMyVideos, 14 getMyVideos,
14 getVideo, 15 getVideo,
15 getVideosList, 16 getVideosList,
16 killallServers, 17 makeGetRequest,
17 root, 18 root,
18 ServerInfo, 19 ServerInfo,
19 setAccessTokensToServers, 20 setAccessTokensToServers,
20 uploadVideo, 21 uploadVideo,
22 waitJobs,
21 webtorrentAdd 23 webtorrentAdd
22} from '../../../../shared/extra-utils' 24} from '../../../../shared/extra-utils'
23import { extname, join } from 'path' 25import { join } from 'path'
24import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
25import { VIDEO_TRANSCODING_FPS } from '../../../../server/initializers/constants' 26import { VIDEO_TRANSCODING_FPS } from '../../../../server/initializers/constants'
26 27
27const expect = chai.expect 28const expect = chai.expect
@@ -121,7 +122,7 @@ describe('Test video transcoding', function () {
121 122
122 expect(videoDetails.files).to.have.lengthOf(4) 123 expect(videoDetails.files).to.have.lengthOf(4)
123 124
124 const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') 125 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4')
125 const probe = await audio.get(path) 126 const probe = await audio.get(path)
126 127
127 if (probe.audioStream) { 128 if (probe.audioStream) {
@@ -152,7 +153,7 @@ describe('Test video transcoding', function () {
152 const videoDetails: VideoDetails = res2.body 153 const videoDetails: VideoDetails = res2.body
153 154
154 expect(videoDetails.files).to.have.lengthOf(4) 155 expect(videoDetails.files).to.have.lengthOf(4)
155 const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') 156 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4')
156 const probe = await audio.get(path) 157 const probe = await audio.get(path)
157 expect(probe).to.not.have.property('audioStream') 158 expect(probe).to.not.have.property('audioStream')
158 } 159 }
@@ -179,7 +180,7 @@ describe('Test video transcoding', function () {
179 expect(videoDetails.files).to.have.lengthOf(4) 180 expect(videoDetails.files).to.have.lengthOf(4)
180 const fixturePath = buildAbsoluteFixturePath(videoAttributes.fixture) 181 const fixturePath = buildAbsoluteFixturePath(videoAttributes.fixture)
181 const fixtureVideoProbe = await audio.get(fixturePath) 182 const fixtureVideoProbe = await audio.get(fixturePath)
182 const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') 183 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4')
183 const videoProbe = await audio.get(path) 184 const videoProbe = await audio.get(path)
184 if (videoProbe.audioStream && fixtureVideoProbe.audioStream) { 185 if (videoProbe.audioStream && fixtureVideoProbe.audioStream) {
185 const toOmit = [ 'max_bit_rate', 'duration', 'duration_ts', 'nb_frames', 'start_time', 'start_pts' ] 186 const toOmit = [ 'max_bit_rate', 'duration', 'duration_ts', 'nb_frames', 'start_time', 'start_pts' ]
@@ -216,13 +217,13 @@ describe('Test video transcoding', function () {
216 expect(videoDetails.files[ 3 ].fps).to.be.below(31) 217 expect(videoDetails.files[ 3 ].fps).to.be.below(31)
217 218
218 for (const resolution of [ '240', '360', '480' ]) { 219 for (const resolution of [ '240', '360', '480' ]) {
219 const path = join(root(), 'test2', 'videos', video.uuid + '-' + resolution + '.mp4') 220 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4')
220 const fps = await getVideoFileFPS(path) 221 const fps = await getVideoFileFPS(path)
221 222
222 expect(fps).to.be.below(31) 223 expect(fps).to.be.below(31)
223 } 224 }
224 225
225 const path = join(root(), 'test2', 'videos', video.uuid + '-720.mp4') 226 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-720.mp4')
226 const fps = await getVideoFileFPS(path) 227 const fps = await getVideoFileFPS(path)
227 228
228 expect(fps).to.be.above(58).and.below(62) 229 expect(fps).to.be.above(58).and.below(62)
@@ -310,7 +311,7 @@ describe('Test video transcoding', function () {
310 const video = res.body.data.find(v => v.name === videoAttributes.name) 311 const video = res.body.data.find(v => v.name === videoAttributes.name)
311 312
312 for (const resolution of ['240', '360', '480', '720', '1080']) { 313 for (const resolution of ['240', '360', '480', '720', '1080']) {
313 const path = join(root(), 'test2', 'videos', video.uuid + '-' + resolution + '.mp4') 314 const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4')
314 const bitrate = await getVideoFileBitrate(path) 315 const bitrate = await getVideoFileBitrate(path)
315 const fps = await getVideoFileFPS(path) 316 const fps = await getVideoFileFPS(path)
316 const resolution2 = await getVideoFileResolution(path) 317 const resolution2 = await getVideoFileResolution(path)
@@ -324,6 +325,15 @@ describe('Test video transcoding', function () {
324 it('Should accept and transcode additional extensions', async function () { 325 it('Should accept and transcode additional extensions', async function () {
325 this.timeout(300000) 326 this.timeout(300000)
326 327
328 let tempFixturePath: string
329
330 {
331 tempFixturePath = await generateHighBitrateVideo()
332
333 const bitrate = await getVideoFileBitrate(tempFixturePath)
334 expect(bitrate).to.be.above(getMaxBitrate(VideoResolution.H_1080P, 60, VIDEO_TRANSCODING_FPS))
335 }
336
327 for (const fixture of [ 'video_short.mkv', 'video_short.avi' ]) { 337 for (const fixture of [ 'video_short.mkv', 'video_short.avi' ]) {
328 const videoAttributes = { 338 const videoAttributes = {
329 name: fixture, 339 name: fixture,
@@ -349,6 +359,63 @@ describe('Test video transcoding', function () {
349 } 359 }
350 }) 360 })
351 361
362 it('Should correctly detect if quick transcode is possible', async function () {
363 this.timeout(10000)
364
365 expect(await canDoQuickTranscode(buildAbsoluteFixturePath('video_short.mp4'))).to.be.true
366 expect(await canDoQuickTranscode(buildAbsoluteFixturePath('video_short.webm'))).to.be.false
367 })
368
369 it('Should merge an audio file with the preview file', async function () {
370 this.timeout(60000)
371
372 const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' }
373 await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg)
374
375 await waitJobs(servers)
376
377 for (const server of servers) {
378 const res = await getVideosList(server.url)
379
380 const video = res.body.data.find(v => v.name === 'audio_with_preview')
381 const res2 = await getVideo(server.url, video.id)
382 const videoDetails: VideoDetails = res2.body
383
384 expect(videoDetails.files).to.have.lengthOf(1)
385
386 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 })
387 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 })
388
389 const magnetUri = videoDetails.files[ 0 ].magnetUri
390 expect(magnetUri).to.contain('.mp4')
391 }
392 })
393
394 it('Should upload an audio file and choose a default background image', async function () {
395 this.timeout(60000)
396
397 const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' }
398 await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg)
399
400 await waitJobs(servers)
401
402 for (const server of servers) {
403 const res = await getVideosList(server.url)
404
405 const video = res.body.data.find(v => v.name === 'audio_without_preview')
406 const res2 = await getVideo(server.url, video.id)
407 const videoDetails = res2.body
408
409 expect(videoDetails.files).to.have.lengthOf(1)
410
411 await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 })
412 await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 })
413
414 const magnetUri = videoDetails.files[ 0 ].magnetUri
415 expect(magnetUri).to.contain('.mp4')
416 }
417 })
418
352 after(async function () { 419 after(async function () {
353 await cleanupTests(servers) 420 await cleanupTests(servers)
354 }) 421 })
diff --git a/server/tests/api/videos/videos-views-cleaner.ts b/server/tests/api/videos/videos-views-cleaner.ts
index c21d46d56..fbddd40f4 100644
--- a/server/tests/api/videos/videos-views-cleaner.ts
+++ b/server/tests/api/videos/videos-views-cleaner.ts
@@ -10,7 +10,7 @@ import {
10 flushAndRunServer, 10 flushAndRunServer,
11 ServerInfo, 11 ServerInfo,
12 setAccessTokensToServers, 12 setAccessTokensToServers,
13 uploadVideo, uploadVideoAndGetId, viewVideo, wait, countVideoViewsOf, doubleFollow, waitJobs, cleanupTests 13 uploadVideo, uploadVideoAndGetId, viewVideo, wait, countVideoViewsOf, doubleFollow, waitJobs, cleanupTests, closeAllSequelize
14} from '../../../../shared/extra-utils' 14} from '../../../../shared/extra-utils'
15import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews' 15import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews'
16import { VideosOverview } from '../../../../shared/models/overviews' 16import { VideosOverview } from '../../../../shared/models/overviews'
@@ -58,14 +58,14 @@ describe('Test video views cleaner', function () {
58 58
59 { 59 {
60 for (const server of servers) { 60 for (const server of servers) {
61 const total = await countVideoViewsOf(server.serverNumber, videoIdServer1) 61 const total = await countVideoViewsOf(server.internalServerNumber, videoIdServer1)
62 expect(total).to.equal(2) 62 expect(total).to.equal(2)
63 } 63 }
64 } 64 }
65 65
66 { 66 {
67 for (const server of servers) { 67 for (const server of servers) {
68 const total = await countVideoViewsOf(server.serverNumber, videoIdServer2) 68 const total = await countVideoViewsOf(server.internalServerNumber, videoIdServer2)
69 expect(total).to.equal(2) 69 expect(total).to.equal(2)
70 } 70 }
71 } 71 }
@@ -74,8 +74,6 @@ describe('Test video views cleaner', function () {
74 it('Should clean old video views', async function () { 74 it('Should clean old video views', async function () {
75 this.timeout(50000) 75 this.timeout(50000)
76 76
77 this.timeout(50000)
78
79 killallServers([ servers[0] ]) 77 killallServers([ servers[0] ])
80 78
81 await reRunServer(servers[0], { views: { videos: { remote: { max_age: '5 seconds' } } } }) 79 await reRunServer(servers[0], { views: { videos: { remote: { max_age: '5 seconds' } } } })
@@ -86,21 +84,23 @@ describe('Test video views cleaner', function () {
86 84
87 { 85 {
88 for (const server of servers) { 86 for (const server of servers) {
89 const total = await countVideoViewsOf(server.serverNumber, videoIdServer1) 87 const total = await countVideoViewsOf(server.internalServerNumber, videoIdServer1)
90 expect(total).to.equal(2) 88 expect(total).to.equal(2)
91 } 89 }
92 } 90 }
93 91
94 { 92 {
95 const totalServer1 = await countVideoViewsOf(servers[0].serverNumber, videoIdServer2) 93 const totalServer1 = await countVideoViewsOf(servers[0].internalServerNumber, videoIdServer2)
96 expect(totalServer1).to.equal(0) 94 expect(totalServer1).to.equal(0)
97 95
98 const totalServer2 = await countVideoViewsOf(servers[1].serverNumber, videoIdServer2) 96 const totalServer2 = await countVideoViewsOf(servers[1].internalServerNumber, videoIdServer2)
99 expect(totalServer2).to.equal(2) 97 expect(totalServer2).to.equal(2)
100 } 98 }
101 }) 99 })
102 100
103 after(async function () { 101 after(async function () {
102 await closeAllSequelize(servers)
103
104 await cleanupTests(servers) 104 await cleanupTests(servers)
105 }) 105 })
106}) 106})
diff --git a/server/tests/cli/optimize-old-videos.ts b/server/tests/cli/optimize-old-videos.ts
index 5e12c0089..3822fca42 100644
--- a/server/tests/cli/optimize-old-videos.ts
+++ b/server/tests/cli/optimize-old-videos.ts
@@ -8,14 +8,16 @@ import {
8 doubleFollow, 8 doubleFollow,
9 execCLI, 9 execCLI,
10 flushAndRunMultipleServers, 10 flushAndRunMultipleServers,
11 flushTests, generateHighBitrateVideo, 11 generateHighBitrateVideo,
12 getEnvCli, 12 getEnvCli,
13 getVideo, 13 getVideo,
14 getVideosList, 14 getVideosList,
15 killallServers, root, 15 root,
16 ServerInfo, 16 ServerInfo,
17 setAccessTokensToServers, 17 setAccessTokensToServers,
18 uploadVideo, viewVideo, wait 18 uploadVideo,
19 viewVideo,
20 wait
19} from '../../../shared/extra-utils' 21} from '../../../shared/extra-utils'
20import { waitJobs } from '../../../shared/extra-utils/server/jobs' 22import { waitJobs } from '../../../shared/extra-utils/server/jobs'
21import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../helpers/ffmpeg-utils' 23import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../helpers/ffmpeg-utils'
@@ -102,7 +104,7 @@ describe('Test optimize old videos', function () {
102 104
103 expect(file.size).to.be.below(5000000) 105 expect(file.size).to.be.below(5000000)
104 106
105 const path = join(root(), 'test1', 'videos', video.uuid + '-' + file.resolution.id + '.mp4') 107 const path = join(root(), 'test' + servers[0].internalServerNumber, 'videos', video.uuid + '-' + file.resolution.id + '.mp4')
106 const bitrate = await getVideoFileBitrate(path) 108 const bitrate = await getVideoFileBitrate(path)
107 const fps = await getVideoFileFPS(path) 109 const fps = await getVideoFileFPS(path)
108 const resolution = await getVideoFileResolution(path) 110 const resolution = await getVideoFileResolution(path)
diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts
index 0dcdf09cf..437470327 100644
--- a/server/tests/feeds/feeds.ts
+++ b/server/tests/feeds/feeds.ts
@@ -7,13 +7,13 @@ import {
7 createUser, 7 createUser,
8 doubleFollow, 8 doubleFollow,
9 flushAndRunMultipleServers, 9 flushAndRunMultipleServers,
10 flushTests, 10 getJSONfeed,
11 getJSONfeed, getMyUserInformation, 11 getMyUserInformation,
12 getXMLfeed, 12 getXMLfeed,
13 killallServers,
14 ServerInfo, 13 ServerInfo,
15 setAccessTokensToServers, 14 setAccessTokensToServers,
16 uploadVideo, userLogin 15 uploadVideo,
16 userLogin
17} from '../../../shared/extra-utils' 17} from '../../../shared/extra-utils'
18import * as libxmljs from 'libxmljs' 18import * as libxmljs from 'libxmljs'
19import { addVideoCommentThread } from '../../../shared/extra-utils/videos/video-comments' 19import { addVideoCommentThread } from '../../../shared/extra-utils/videos/video-comments'
@@ -28,10 +28,10 @@ const expect = chai.expect
28describe('Test syndication feeds', () => { 28describe('Test syndication feeds', () => {
29 let servers: ServerInfo[] = [] 29 let servers: ServerInfo[] = []
30 let userAccessToken: string 30 let userAccessToken: string
31 let rootAccountUUID: string 31 let rootAccountId: number
32 let rootChannelUUID: string 32 let rootChannelId: number
33 let userAccountUUID: string 33 let userAccountId: number
34 let userChannelUUID: string 34 let userChannelId: number
35 35
36 before(async function () { 36 before(async function () {
37 this.timeout(120000) 37 this.timeout(120000)
@@ -45,8 +45,8 @@ describe('Test syndication feeds', () => {
45 { 45 {
46 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) 46 const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
47 const user: User = res.body 47 const user: User = res.body
48 rootAccountUUID = user.account.uuid 48 rootAccountId = user.account.id
49 rootChannelUUID = user.videoChannels[0].uuid 49 rootChannelId = user.videoChannels[0].id
50 } 50 }
51 51
52 { 52 {
@@ -56,8 +56,8 @@ describe('Test syndication feeds', () => {
56 56
57 const res = await getMyUserInformation(servers[0].url, userAccessToken) 57 const res = await getMyUserInformation(servers[0].url, userAccessToken)
58 const user: User = res.body 58 const user: User = res.body
59 userAccountUUID = user.account.uuid 59 userAccountId = user.account.id
60 userChannelUUID = user.videoChannels[0].uuid 60 userChannelId = user.videoChannels[0].id
61 } 61 }
62 62
63 { 63 {
@@ -127,71 +127,71 @@ describe('Test syndication feeds', () => {
127 }) 127 })
128 128
129 it('Should filter by account', async function () { 129 it('Should filter by account', async function () {
130 {
131 const json = await getJSONfeed(servers[0].url, 'videos', { accountId: rootAccountId })
132 const jsonObj = JSON.parse(json.text)
133 expect(jsonObj.items.length).to.be.equal(1)
134 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
135 expect(jsonObj.items[ 0 ].author.name).to.equal('root')
136 }
137
138 {
139 const json = await getJSONfeed(servers[0].url, 'videos', { accountId: userAccountId })
140 const jsonObj = JSON.parse(json.text)
141 expect(jsonObj.items.length).to.be.equal(1)
142 expect(jsonObj.items[ 0 ].title).to.equal('user video')
143 expect(jsonObj.items[ 0 ].author.name).to.equal('john')
144 }
145
130 for (const server of servers) { 146 for (const server of servers) {
131 { 147 {
132 const json = await getJSONfeed(server.url, 'videos', { accountId: rootAccountUUID }) 148 const json = await getJSONfeed(server.url, 'videos', { accountName: 'root@localhost:' + servers[0].port })
133 const jsonObj = JSON.parse(json.text) 149 const jsonObj = JSON.parse(json.text)
134 expect(jsonObj.items.length).to.be.equal(1) 150 expect(jsonObj.items.length).to.be.equal(1)
135 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') 151 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
136 expect(jsonObj.items[ 0 ].author.name).to.equal('root')
137 } 152 }
138 153
139 { 154 {
140 const json = await getJSONfeed(server.url, 'videos', { accountId: userAccountUUID }) 155 const json = await getJSONfeed(server.url, 'videos', { accountName: 'john@localhost:' + servers[0].port })
141 const jsonObj = JSON.parse(json.text) 156 const jsonObj = JSON.parse(json.text)
142 expect(jsonObj.items.length).to.be.equal(1) 157 expect(jsonObj.items.length).to.be.equal(1)
143 expect(jsonObj.items[ 0 ].title).to.equal('user video') 158 expect(jsonObj.items[ 0 ].title).to.equal('user video')
144 expect(jsonObj.items[ 0 ].author.name).to.equal('john')
145 } 159 }
146 } 160 }
161 })
147 162
163 it('Should filter by video channel', async function () {
148 { 164 {
149 const json = await getJSONfeed(servers[0].url, 'videos', { accountName: 'root' }) 165 const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: rootChannelId })
150 const jsonObj = JSON.parse(json.text) 166 const jsonObj = JSON.parse(json.text)
151 expect(jsonObj.items.length).to.be.equal(1) 167 expect(jsonObj.items.length).to.be.equal(1)
152 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') 168 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
169 expect(jsonObj.items[ 0 ].author.name).to.equal('root')
153 } 170 }
154 171
155 { 172 {
156 const json = await getJSONfeed(servers[0].url, 'videos', { accountName: 'john' }) 173 const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: userChannelId })
157 const jsonObj = JSON.parse(json.text) 174 const jsonObj = JSON.parse(json.text)
158 expect(jsonObj.items.length).to.be.equal(1) 175 expect(jsonObj.items.length).to.be.equal(1)
159 expect(jsonObj.items[ 0 ].title).to.equal('user video') 176 expect(jsonObj.items[ 0 ].title).to.equal('user video')
177 expect(jsonObj.items[ 0 ].author.name).to.equal('john')
160 } 178 }
161 })
162 179
163 it('Should filter by video channel', async function () {
164 for (const server of servers) { 180 for (const server of servers) {
165 { 181 {
166 const json = await getJSONfeed(server.url, 'videos', { videoChannelId: rootChannelUUID }) 182 const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'root_channel@localhost:' + servers[0].port })
167 const jsonObj = JSON.parse(json.text) 183 const jsonObj = JSON.parse(json.text)
168 expect(jsonObj.items.length).to.be.equal(1) 184 expect(jsonObj.items.length).to.be.equal(1)
169 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') 185 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
170 expect(jsonObj.items[ 0 ].author.name).to.equal('root')
171 } 186 }
172 187
173 { 188 {
174 const json = await getJSONfeed(server.url, 'videos', { videoChannelId: userChannelUUID }) 189 const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'john_channel@localhost:' + servers[0].port })
175 const jsonObj = JSON.parse(json.text) 190 const jsonObj = JSON.parse(json.text)
176 expect(jsonObj.items.length).to.be.equal(1) 191 expect(jsonObj.items.length).to.be.equal(1)
177 expect(jsonObj.items[ 0 ].title).to.equal('user video') 192 expect(jsonObj.items[ 0 ].title).to.equal('user video')
178 expect(jsonObj.items[ 0 ].author.name).to.equal('john')
179 } 193 }
180 } 194 }
181
182 {
183 const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelName: 'root_channel' })
184 const jsonObj = JSON.parse(json.text)
185 expect(jsonObj.items.length).to.be.equal(1)
186 expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
187 }
188
189 {
190 const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelName: 'john_channel' })
191 const jsonObj = JSON.parse(json.text)
192 expect(jsonObj.items.length).to.be.equal(1)
193 expect(jsonObj.items[ 0 ].title).to.equal('user video')
194 }
195 }) 195 })
196 }) 196 })
197 197
diff --git a/server/tests/fixtures/preview.jpg b/server/tests/fixtures/preview.jpg
index c40ece838..cb5692281 100644
--- a/server/tests/fixtures/preview.jpg
+++ b/server/tests/fixtures/preview.jpg
Binary files differ
diff --git a/server/tests/fixtures/sample.ogg b/server/tests/fixtures/sample.ogg
new file mode 100644
index 000000000..0d7f43eb7
--- /dev/null
+++ b/server/tests/fixtures/sample.ogg
Binary files differ
diff --git a/server/tests/fixtures/video_short1-preview.webm.jpg b/server/tests/fixtures/video_short1-preview.webm.jpg
index d2a068b78..157d3ca9a 100644
--- a/server/tests/fixtures/video_short1-preview.webm.jpg
+++ b/server/tests/fixtures/video_short1-preview.webm.jpg
Binary files differ
diff --git a/server/tools/package.json b/server/tools/package.json
new file mode 100644
index 000000000..2d13d41cc
--- /dev/null
+++ b/server/tools/package.json
@@ -0,0 +1,12 @@
1{
2 "name": "@peertube/cli",
3 "version": "1.0.0",
4 "private": true,
5 "dependencies": {
6 "application-config": "^1.0.1",
7 "webtorrent-hybrid": "^2.1.0"
8 },
9 "summon": {
10 "silent": true
11 }
12}
diff --git a/server/tools/peertube-watch.ts b/server/tools/peertube-watch.ts
index bf7274aab..7c27c1364 100644
--- a/server/tools/peertube-watch.ts
+++ b/server/tools/peertube-watch.ts
@@ -1,21 +1,15 @@
1import * as program from 'commander' 1import * as program from 'commander'
2import * as summon from 'summon-install'
3import { join } from 'path' 2import { join } from 'path'
4import { execSync } from 'child_process' 3import { execSync } from 'child_process'
5import { root } from '../helpers/core-utils'
6
7let videoURL
8 4
9program 5program
10 .name('watch') 6 .name('watch')
11 .arguments('<url>') 7 .arguments('<url>')
12 .option('-g, --gui <player>', 'player type', /^(airplay|stdout|chromecast|mpv|vlc|mplayer|ascii|xbmc)$/i, 'ascii') 8 .option('-g, --gui <player>', 'player type', /^(airplay|stdout|chromecast|mpv|vlc|mplayer|xbmc)$/i, 'vlc')
13 .option('-i, --invert', 'invert colors (ascii player only)', true) 9 .option('-r, --resolution <res>', 'video resolution', '480')
14 .option('-r, --resolution <res>', 'video resolution', /^(240|360|720|1080)$/i, '720')
15 .on('--help', function () { 10 .on('--help', function () {
16 console.log(' Available Players:') 11 console.log(' Available Players:')
17 console.log() 12 console.log()
18 console.log(' - ascii')
19 console.log(' - mpv') 13 console.log(' - mpv')
20 console.log(' - mplayer') 14 console.log(' - mplayer')
21 console.log(' - vlc') 15 console.log(' - vlc')
@@ -24,7 +18,6 @@ program
24 console.log(' - airplay') 18 console.log(' - airplay')
25 console.log(' - chromecast') 19 console.log(' - chromecast')
26 console.log() 20 console.log()
27 console.log(' Note: \'ascii\' is the only option not using WebTorrent and not seeding back the video.')
28 console.log() 21 console.log()
29 console.log(' Examples:') 22 console.log(' Examples:')
30 console.log() 23 console.log()
@@ -33,29 +26,25 @@ program
33 console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10') 26 console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10')
34 console.log() 27 console.log()
35 }) 28 })
36 .action((url) => { 29 .action((url, cmd) => {
37 videoURL = url 30 run(url, cmd)
31 .catch(err => {
32 console.error(err)
33 process.exit(-1)
34 })
38 }) 35 })
39 .parse(process.argv) 36 .parse(process.argv)
40 37
41if (!videoURL) { 38async function run (url: string, program: any) {
42 console.error('<url> positional argument is required.') 39 if (!url) {
43 process.exit(-1) 40 console.error('<url> positional argument is required.')
44} else { program['url'] = videoURL } 41 process.exit(-1)
42 }
45 43
46handler(program) 44 const cmd = 'node ' + join(__dirname, 'node_modules', 'webtorrent-hybrid', 'bin', 'cmd.js')
45 const args = ` --${program.gui} ` +
46 url.replace('videos/watch', 'download/torrents') +
47 `-${program.resolution}.torrent`
47 48
48function handler (argv) { 49 execSync(cmd + args)
49 if (argv['gui'] === 'ascii') {
50 summon('peerterminal')
51 const peerterminal = summon('peerterminal')
52 peerterminal([ '--link', videoURL, '--invert', argv['invert'] ])
53 } else {
54 summon('webtorrent-hybrid')
55 const CMD = 'node ' + join(root(), 'node_modules', 'webtorrent-hybrid', 'bin', 'cmd.js')
56 const CMDargs = ` --${argv.gui} ` +
57 argv['url'].replace('videos/watch', 'download/torrents') +
58 `-${argv.resolution}.torrent`
59 execSync(CMD + CMDargs)
60 }
61} 50}
diff --git a/server/tools/peertube.ts b/server/tools/peertube.ts
index 5d3ab2815..5d3ab2815 100755..100644
--- a/server/tools/peertube.ts
+++ b/server/tools/peertube.ts
diff --git a/server/tools/tsconfig.json b/server/tools/tsconfig.json
new file mode 100644
index 000000000..f8a1c705c
--- /dev/null
+++ b/server/tools/tsconfig.json
@@ -0,0 +1,4 @@
1{
2 "extends": "../../tsconfig.json",
3 "exclude": [ ] // Overwrite exclude property
4}
diff --git a/server/tools/yarn.lock b/server/tools/yarn.lock
new file mode 100644
index 000000000..3c3778d3f
--- /dev/null
+++ b/server/tools/yarn.lock
@@ -0,0 +1,1970 @@
1# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2# yarn lockfile v1
3
4
5abbrev@1:
6 version "1.1.1"
7 resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
8 integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
9
10addr-to-ip-port@^1.0.1, addr-to-ip-port@^1.4.2:
11 version "1.5.1"
12 resolved "https://registry.yarnpkg.com/addr-to-ip-port/-/addr-to-ip-port-1.5.1.tgz#bfada13fd6aeeeac19f1e9f7d84b4bbab45e5208"
13 integrity sha512-bA+dyydTNuQtrEDJ0g9eR7XabNhvrM5yZY0hvTbNK3yvoeC73ZqMES6E1cEqH9WPxs4uMtMsOjfwS4FmluhsAA==
14
15airplay-js@^0.3.0:
16 version "0.3.0"
17 resolved "https://registry.yarnpkg.com/airplay-js/-/airplay-js-0.3.0.tgz#16bac2ef91b31249382924bfdeeabaddc9db7398"
18 integrity sha1-FrrC75GzEkk4KSS/3uq63cnbc5g=
19 dependencies:
20 mdns-js "0.5.0"
21 plist-with-patches "0.5.1"
22
23ansi-regex@^2.0.0:
24 version "2.1.1"
25 resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
26 integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
27
28ansi-regex@^3.0.0:
29 version "3.0.0"
30 resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
31 integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
32
33application-config-path@^0.1.0:
34 version "0.1.0"
35 resolved "https://registry.yarnpkg.com/application-config-path/-/application-config-path-0.1.0.tgz#193c5f0a86541a4c66fba1e2dc38583362ea5e8f"
36 integrity sha1-GTxfCoZUGkxm+6Hi3DhYM2LqXo8=
37
38application-config@^1.0.1:
39 version "1.0.1"
40 resolved "https://registry.yarnpkg.com/application-config/-/application-config-1.0.1.tgz#5aa2e2a5ed6abd2e5d1d473d3596f574044fe9e7"
41 integrity sha1-WqLipe1qvS5dHUc9NZb1dARP6ec=
42 dependencies:
43 application-config-path "^0.1.0"
44 mkdirp "^0.5.1"
45
46aproba@^1.0.3:
47 version "1.2.0"
48 resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
49 integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
50
51are-we-there-yet@~1.1.2:
52 version "1.1.5"
53 resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
54 integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
55 dependencies:
56 delegates "^1.0.0"
57 readable-stream "^2.0.6"
58
59ascli@~0.3:
60 version "0.3.0"
61 resolved "https://registry.yarnpkg.com/ascli/-/ascli-0.3.0.tgz#5e66230e5219fe3e8952a4efb4f20fae596a813a"
62 integrity sha1-XmYjDlIZ/j6JUqTvtPIPrllqgTo=
63 dependencies:
64 colour latest
65 optjs latest
66
67async-limiter@~1.0.0:
68 version "1.0.0"
69 resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
70 integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
71
72balanced-match@^1.0.0:
73 version "1.0.0"
74 resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
75 integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
76
77bencode@^2.0.0:
78 version "2.0.1"
79 resolved "https://registry.yarnpkg.com/bencode/-/bencode-2.0.1.tgz#667a6a31c5e038d558608333da6b7c94e836c85b"
80 integrity sha512-2uhEl8FdjSBUyb69qDTgOEeeqDTa+n3yMQzLW0cOzNf1Ow5bwcg3idf+qsWisIKRH8Bk8oC7UXL8irRcPA8ZEQ==
81 dependencies:
82 safe-buffer "^5.1.1"
83
84binary-search@^1.3.4:
85 version "1.3.5"
86 resolved "https://registry.yarnpkg.com/binary-search/-/binary-search-1.3.5.tgz#479ad009589e0273cf54e5d74ab1546c489078ce"
87 integrity sha512-RHFP0AdU6KAB0CCZsRMU2CJTk2EpL8GLURT+4gilpjr1f/7M91FgUMnXuQLmf3OKLet34gjuNFwO7e4agdX5pw==
88
89bitfield@^2.0.0:
90 version "2.0.0"
91 resolved "https://registry.yarnpkg.com/bitfield/-/bitfield-2.0.0.tgz#fbe6767592fe5b4c87ecf1d04126294cc1bfa837"
92 integrity sha512-4xM4DYejOHQ/qWBfeqBXNA4mJ12PwcOibFYnH1kYh5U9BHciCqEJBqGNVnMJXUhm8mflujNRLSv7IiVQxovgjw==
93
94bittorrent-dht@^9.0.0:
95 version "9.0.0"
96 resolved "https://registry.yarnpkg.com/bittorrent-dht/-/bittorrent-dht-9.0.0.tgz#08d5ebb51ed91d7e3eea5c275554f4323fb523e5"
97 integrity sha512-X5ax4G/PLtEPfqOUjqDZ2nmPENndWRMK4sT2jcQ4sXor904zhR40r4KqTyTvWYAljh5/hPPqM9DCUUtqWzRXoQ==
98 dependencies:
99 bencode "^2.0.0"
100 buffer-equals "^1.0.3"
101 debug "^3.1.0"
102 inherits "^2.0.1"
103 k-bucket "^5.0.0"
104 k-rpc "^5.0.0"
105 last-one-wins "^1.0.4"
106 lru "^3.1.0"
107 randombytes "^2.0.5"
108 record-cache "^1.0.2"
109 safe-buffer "^5.0.1"
110 simple-sha1 "^2.1.0"
111
112bittorrent-peerid@^1.0.2:
113 version "1.3.0"
114 resolved "https://registry.yarnpkg.com/bittorrent-peerid/-/bittorrent-peerid-1.3.0.tgz#a435d3b267c887c586c528b53359845905d7c158"
115 integrity sha512-SYd5H3RbN1ex+TrWAKXkEkASFWxAR7Tk6iLt9tfAT9ehBvZb/Y3AQDVRVJynlrixcWpnmsLYKI7tkRWgp7ORoQ==
116
117bittorrent-protocol@^3.0.0:
118 version "3.0.1"
119 resolved "https://registry.yarnpkg.com/bittorrent-protocol/-/bittorrent-protocol-3.0.1.tgz#d3948f4d2b09d538095f7e5f93f64ba5df6b5c2a"
120 integrity sha512-hnvOzAu9u+2H0OLLL5byoFdz6oz5f3bx5f7R+ItUohTHMq9TgUhEJfcjo7xWtQHSKOVciYWwYTJ4EjczF5RX2A==
121 dependencies:
122 bencode "^2.0.0"
123 bitfield "^2.0.0"
124 debug "^3.1.0"
125 randombytes "^2.0.5"
126 readable-stream "^2.3.2"
127 speedometer "^1.0.0"
128 unordered-array-remove "^1.0.2"
129 xtend "^4.0.0"
130
131bittorrent-tracker@^9.0.0:
132 version "9.11.0"
133 resolved "https://registry.yarnpkg.com/bittorrent-tracker/-/bittorrent-tracker-9.11.0.tgz#9911f9c14e5a29f84990a0c31b3d83dd16eb2876"
134 integrity sha512-T1zvW/kSeEnWT4I3JE+6c7aZbO5jtleZyQe911SyzIxFF9DvtUNWXud3p5ZUkXaoI2xXwfpvlks5VFj5SKEB+A==
135 dependencies:
136 bencode "^2.0.0"
137 bittorrent-peerid "^1.0.2"
138 bn.js "^4.4.0"
139 compact2string "^1.2.0"
140 debug "^4.0.1"
141 ip "^1.0.1"
142 lru "^3.0.0"
143 minimist "^1.1.1"
144 once "^1.3.0"
145 random-iterate "^1.0.1"
146 randombytes "^2.0.3"
147 run-parallel "^1.1.2"
148 run-series "^1.0.2"
149 safe-buffer "^5.0.0"
150 simple-get "^3.0.0"
151 simple-peer "^9.0.0"
152 simple-websocket "^7.0.1"
153 string2compact "^1.1.1"
154 uniq "^1.0.1"
155 unordered-array-remove "^1.0.2"
156 ws "^6.0.0"
157 optionalDependencies:
158 bufferutil "^4.0.0"
159 utf-8-validate "^5.0.1"
160
161blob-to-buffer@^1.2.6:
162 version "1.2.8"
163 resolved "https://registry.yarnpkg.com/blob-to-buffer/-/blob-to-buffer-1.2.8.tgz#78eeeb332f1280ed0ca6fb2b60693a8c6d36903a"
164 integrity sha512-re0AIxakF504MgeMtIyJkVcZ8T5aUxtp/QmTMlmjyb3P44E1BEv5x3LATBGApWAJATyXHtkXRD+gWTmeyYLiQA==
165
166block-stream2@^1.0.0:
167 version "1.1.0"
168 resolved "https://registry.yarnpkg.com/block-stream2/-/block-stream2-1.1.0.tgz#c738e3a91ba977ebb5e1fef431e13ca11d8639e2"
169 integrity sha1-xzjjqRupd+u14f70MeE8oR2GOeI=
170 dependencies:
171 defined "^1.0.0"
172 inherits "^2.0.1"
173 readable-stream "^2.0.4"
174
175bn.js@^4.4.0:
176 version "4.11.8"
177 resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
178 integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
179
180brace-expansion@^1.1.7:
181 version "1.1.11"
182 resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
183 integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
184 dependencies:
185 balanced-match "^1.0.0"
186 concat-map "0.0.1"
187
188browserify-package-json@^1.0.0:
189 version "1.0.1"
190 resolved "https://registry.yarnpkg.com/browserify-package-json/-/browserify-package-json-1.0.1.tgz#98dde8aa5c561fd6d3fe49bbaa102b74b396fdea"
191 integrity sha1-mN3oqlxWH9bT/km7qhArdLOW/eo=
192
193buffer-alloc-unsafe@^1.1.0:
194 version "1.1.0"
195 resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
196 integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
197
198buffer-alloc@^1.1.0, buffer-alloc@^1.2.0:
199 version "1.2.0"
200 resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
201 integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
202 dependencies:
203 buffer-alloc-unsafe "^1.1.0"
204 buffer-fill "^1.0.0"
205
206buffer-equals@^1.0.3, buffer-equals@^1.0.4:
207 version "1.0.4"
208 resolved "https://registry.yarnpkg.com/buffer-equals/-/buffer-equals-1.0.4.tgz#0353b54fd07fd9564170671ae6f66b9cf10d27f5"
209 integrity sha1-A1O1T9B/2VZBcGca5vZrnPENJ/U=
210
211buffer-fill@^1.0.0:
212 version "1.0.0"
213 resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
214 integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
215
216buffer-from@^1.0.0, buffer-from@^1.1.0:
217 version "1.1.1"
218 resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
219 integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
220
221buffer-indexof@^1.0.0:
222 version "1.1.1"
223 resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c"
224 integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==
225
226bufferutil@^4.0.0:
227 version "4.0.1"
228 resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.1.tgz#3a177e8e5819a1243fe16b63a199951a7ad8d4a7"
229 integrity sha512-xowrxvpxojqkagPcWRQVXZl0YXhRhAtBEIq3VoER1NH5Mw1n1o0ojdspp+GS2J//2gCVyrzQDApQ4unGF+QOoA==
230 dependencies:
231 node-gyp-build "~3.7.0"
232
233bufferview@~1:
234 version "1.0.1"
235 resolved "https://registry.yarnpkg.com/bufferview/-/bufferview-1.0.1.tgz#7afd74a45f937fa422a1d338c08bbfdc76cd725d"
236 integrity sha1-ev10pF+Tf6QiodM4wIu/3HbNcl0=
237
238"bytebuffer@~3 >=3.5":
239 version "3.5.5"
240 resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-3.5.5.tgz#7a6faf1a13514b083f1fcf9541c4c9bfbe7e7fd3"
241 integrity sha1-em+vGhNRSwg/H8+VQcTJv75+f9M=
242 dependencies:
243 bufferview "~1"
244 long "~2 >=2.2.3"
245
246camelcase@^3.0.0:
247 version "3.0.0"
248 resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
249 integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
250
251castv2-client@^1.1.0:
252 version "1.2.0"
253 resolved "https://registry.yarnpkg.com/castv2-client/-/castv2-client-1.2.0.tgz#a9193b1a5448b8cb9a0415bd021c8811ed7b0544"
254 integrity sha1-qRk7GlRIuMuaBBW9AhyIEe17BUQ=
255 dependencies:
256 castv2 "~0.1.4"
257 debug "^2.2.0"
258
259castv2@~0.1.4:
260 version "0.1.9"
261 resolved "https://registry.yarnpkg.com/castv2/-/castv2-0.1.9.tgz#d0b0fab1fd06b0d9cca636886716ec1293a5905a"
262 integrity sha1-0LD6sf0GsNnMpjaIZxbsEpOlkFo=
263 dependencies:
264 debug "^2.2.0"
265 protobufjs "^3.2.2"
266
267chownr@^1.1.1:
268 version "1.1.1"
269 resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
270 integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
271
272chromecasts@^1.5.3:
273 version "1.9.1"
274 resolved "https://registry.yarnpkg.com/chromecasts/-/chromecasts-1.9.1.tgz#67b162e8414d57d6106c49fe4a0e9b08f20bbd12"
275 integrity sha512-nsXv7ufgrpC8s5DUm6FJEa2XJ2VvE9FmbTVi6r4zGreTFTTSRSJjvqVEqLUFX/fGo/zbSre3zdoV+Pu9DGLz0A==
276 dependencies:
277 castv2-client "^1.1.0"
278 debug "^2.1.3"
279 dns-txt "^2.0.2"
280 mime "^1.3.4"
281 multicast-dns "^6.0.1"
282 simple-get "^2.0.0"
283 thunky "^0.1.0"
284 xml2js "^0.4.8"
285 optionalDependencies:
286 node-ssdp "^2.2.0"
287
288chunk-store-stream@^3.0.1:
289 version "3.0.1"
290 resolved "https://registry.yarnpkg.com/chunk-store-stream/-/chunk-store-stream-3.0.1.tgz#8e0d739226dcb386f44447b82a005b597a1d41d9"
291 integrity sha512-GA1NIFDZKElhkjiO6QOyzfK1QbUt6M3gFhUU/aR05JYaDqXbU5d7U92cLvGKdItJEDfojky6NQefy5VL5PpDBA==
292 dependencies:
293 block-stream2 "^1.0.0"
294 readable-stream "^2.0.5"
295
296cliui@^3.2.0:
297 version "3.2.0"
298 resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
299 integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
300 dependencies:
301 string-width "^1.0.1"
302 strip-ansi "^3.0.1"
303 wrap-ansi "^2.0.0"
304
305clivas@^0.2.0:
306 version "0.2.0"
307 resolved "https://registry.yarnpkg.com/clivas/-/clivas-0.2.0.tgz#b8d19188b3243e390f302410bd0cb1622db82649"
308 integrity sha1-uNGRiLMkPjkPMCQQvQyxYi24Jkk=
309
310closest-to@~2.0.0:
311 version "2.0.0"
312 resolved "https://registry.yarnpkg.com/closest-to/-/closest-to-2.0.0.tgz#bb2a860edb7769b62d04821748ae50da24dbefaa"
313 integrity sha1-uyqGDtt3abYtBIIXSK5Q2iTb76o=
314
315code-point-at@^1.0.0:
316 version "1.1.0"
317 resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
318 integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
319
320colour@latest:
321 version "0.7.1"
322 resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778"
323 integrity sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=
324
325compact2string@^1.2.0:
326 version "1.4.1"
327 resolved "https://registry.yarnpkg.com/compact2string/-/compact2string-1.4.1.tgz#8d34929055f8300a13cfc030ad1832e2e53c2e25"
328 integrity sha512-3D+EY5nsRhqnOwDxveBv5T8wGo4DEvYxjDtPGmdOX+gfr5gE92c2RC0w2wa+xEefm07QuVqqcF3nZJUZ92l/og==
329 dependencies:
330 ipaddr.js ">= 0.1.5"
331
332concat-map@0.0.1:
333 version "0.0.1"
334 resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
335 integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
336
337concat-stream@^1.4.8:
338 version "1.6.2"
339 resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
340 integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
341 dependencies:
342 buffer-from "^1.0.0"
343 inherits "^2.0.3"
344 readable-stream "^2.2.2"
345 typedarray "^0.0.6"
346
347console-control-strings@^1.0.0, console-control-strings@~1.1.0:
348 version "1.1.0"
349 resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
350 integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
351
352core-util-is@~1.0.0:
353 version "1.0.2"
354 resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
355 integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
356
357create-torrent@^3.23.1, create-torrent@^3.33.0:
358 version "3.33.0"
359 resolved "https://registry.yarnpkg.com/create-torrent/-/create-torrent-3.33.0.tgz#8a7a2aa2213a799c266c40e4c12f1468ede25105"
360 integrity sha512-KMd0KuvwVUg1grlRd5skG9ZkSbBYDDkAjDUMLnvxdRn0rL7ph3IwoOk7I8u1yLX4HYjGiLVlWYO55YWNNPjJFA==
361 dependencies:
362 bencode "^2.0.0"
363 block-stream2 "^1.0.0"
364 filestream "^4.0.0"
365 flatten "^1.0.2"
366 is-file "^1.0.0"
367 junk "^2.1.0"
368 minimist "^1.1.0"
369 multistream "^2.0.2"
370 once "^1.3.0"
371 piece-length "^1.0.0"
372 readable-stream "^3.0.2"
373 run-parallel "^1.0.0"
374 simple-sha1 "^2.0.0"
375
376debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0:
377 version "2.6.9"
378 resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
379 integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
380 dependencies:
381 ms "2.0.0"
382
383debug@^3.1.0, debug@^3.2.6:
384 version "3.2.6"
385 resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
386 integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
387 dependencies:
388 ms "^2.1.1"
389
390debug@^4.0.1, debug@^4.1.0:
391 version "4.1.1"
392 resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
393 integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
394 dependencies:
395 ms "^2.1.1"
396
397decamelize@^1.1.1:
398 version "1.2.0"
399 resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
400 integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
401
402decompress-response@^3.3.0:
403 version "3.3.0"
404 resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
405 integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
406 dependencies:
407 mimic-response "^1.0.0"
408
409deep-extend@^0.6.0:
410 version "0.6.0"
411 resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
412 integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
413
414defined@^1.0.0:
415 version "1.0.0"
416 resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
417 integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
418
419delegates@^1.0.0:
420 version "1.0.0"
421 resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
422 integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
423
424detect-libc@^1.0.2:
425 version "1.0.3"
426 resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
427 integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
428
429dlnacasts@^0.1.0:
430 version "0.1.0"
431 resolved "https://registry.yarnpkg.com/dlnacasts/-/dlnacasts-0.1.0.tgz#f805211dcac74f6bb3a4d5d5541ad783b1b67d22"
432 integrity sha1-+AUhHcrHT2uzpNXVVBrXg7G2fSI=
433 dependencies:
434 debug "^2.1.3"
435 mime "^1.3.4"
436 node-ssdp "^2.7.1"
437 run-parallel "^1.1.6"
438 simple-get "^2.1.0"
439 thunky "^0.1.0"
440 upnp-mediarenderer-client "^1.2.2"
441 xml2js "^0.4.8"
442
443dns-packet@^1.3.1:
444 version "1.3.1"
445 resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a"
446 integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==
447 dependencies:
448 ip "^1.1.0"
449 safe-buffer "^5.0.1"
450
451dns-txt@^2.0.2:
452 version "2.0.2"
453 resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6"
454 integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=
455 dependencies:
456 buffer-indexof "^1.0.0"
457
458domexception@^1.0.1:
459 version "1.0.1"
460 resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
461 integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==
462 dependencies:
463 webidl-conversions "^4.0.2"
464
465ecstatic@^3.0.0:
466 version "3.3.2"
467 resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.2.tgz#6d1dd49814d00594682c652adb66076a69d46c48"
468 integrity sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==
469 dependencies:
470 he "^1.1.1"
471 mime "^1.6.0"
472 minimist "^1.1.0"
473 url-join "^2.0.5"
474
475elementtree@^0.1.6, elementtree@~0.1.6:
476 version "0.1.7"
477 resolved "https://registry.yarnpkg.com/elementtree/-/elementtree-0.1.7.tgz#9ac91be6e52fb6e6244c4e54a4ac3ed8ae8e29c0"
478 integrity sha1-mskb5uUvtuYkTE5UpKw+2K6OKcA=
479 dependencies:
480 sax "1.1.4"
481
482end-of-stream@^1.1.0:
483 version "1.4.1"
484 resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
485 integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
486 dependencies:
487 once "^1.4.0"
488
489error-ex@^1.2.0:
490 version "1.3.2"
491 resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
492 integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
493 dependencies:
494 is-arrayish "^0.2.1"
495
496executable@^4.0.0:
497 version "4.1.1"
498 resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c"
499 integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==
500 dependencies:
501 pify "^2.2.0"
502
503filestream@^4.0.0:
504 version "4.1.3"
505 resolved "https://registry.yarnpkg.com/filestream/-/filestream-4.1.3.tgz#948fcaade8221f715f5ecaddc54862faaacc9325"
506 integrity sha1-lI/KregiH3FfXsrdxUhi+qrMkyU=
507 dependencies:
508 inherits "^2.0.1"
509 readable-stream "^2.0.5"
510 typedarray-to-buffer "^3.0.0"
511 xtend "^4.0.1"
512
513find-up@^1.0.0:
514 version "1.1.2"
515 resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
516 integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
517 dependencies:
518 path-exists "^2.0.0"
519 pinkie-promise "^2.0.0"
520
521flatten@^1.0.2:
522 version "1.0.2"
523 resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
524 integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=
525
526fs-chunk-store@^1.6.2:
527 version "1.7.0"
528 resolved "https://registry.yarnpkg.com/fs-chunk-store/-/fs-chunk-store-1.7.0.tgz#1c4bcbe93c99af10aa04b65348f2bb27377a4010"
529 integrity sha512-KhjJmZAs2eqfhCb6PdPx4RcZtheGTz86tpTC5JTvqBn/xda+Nb+0C7dCyjOSN7T76H6a56LvH0SVXQMchLXDRw==
530 dependencies:
531 mkdirp "^0.5.1"
532 random-access-file "^2.0.1"
533 randombytes "^2.0.3"
534 rimraf "^2.4.2"
535 run-parallel "^1.1.2"
536 thunky "^1.0.1"
537
538fs-minipass@^1.2.5:
539 version "1.2.6"
540 resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07"
541 integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==
542 dependencies:
543 minipass "^2.2.1"
544
545fs.realpath@^1.0.0:
546 version "1.0.0"
547 resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
548 integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
549
550gauge@~2.7.3:
551 version "2.7.4"
552 resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
553 integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
554 dependencies:
555 aproba "^1.0.3"
556 console-control-strings "^1.0.0"
557 has-unicode "^2.0.0"
558 object-assign "^4.1.0"
559 signal-exit "^3.0.0"
560 string-width "^1.0.1"
561 strip-ansi "^3.0.1"
562 wide-align "^1.1.0"
563
564get-browser-rtc@^1.0.0:
565 version "1.0.2"
566 resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz#bbcd40c8451a7ed4ef5c373b8169a409dd1d11d9"
567 integrity sha1-u81AyEUaftTvXDc7gWmkCd0dEdk=
568
569get-caller-file@^1.0.1:
570 version "1.0.3"
571 resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
572 integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
573
574get-stdin@^6.0.0:
575 version "6.0.0"
576 resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
577 integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
578
579glob@^7.1.3:
580 version "7.1.4"
581 resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
582 integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
583 dependencies:
584 fs.realpath "^1.0.0"
585 inflight "^1.0.4"
586 inherits "2"
587 minimatch "^3.0.4"
588 once "^1.3.0"
589 path-is-absolute "^1.0.0"
590
591graceful-fs@^4.1.2:
592 version "4.1.15"
593 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
594 integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
595
596has-unicode@^2.0.0:
597 version "2.0.1"
598 resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
599 integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
600
601he@^1.1.1:
602 version "1.2.0"
603 resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
604 integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
605
606hosted-git-info@^2.1.4:
607 version "2.7.1"
608 resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
609 integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
610
611iconv-lite@^0.4.4:
612 version "0.4.24"
613 resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
614 integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
615 dependencies:
616 safer-buffer ">= 2.1.2 < 3"
617
618ignore-walk@^3.0.1:
619 version "3.0.1"
620 resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
621 integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==
622 dependencies:
623 minimatch "^3.0.4"
624
625immediate-chunk-store@^2.0.0:
626 version "2.0.0"
627 resolved "https://registry.yarnpkg.com/immediate-chunk-store/-/immediate-chunk-store-2.0.0.tgz#f313fd0cc71396d8911ad031179e1cccfda3da18"
628 integrity sha512-5s6NiCGbtWc+OQA60jrre54w12U7tynIyUNjO5LJjNA5lWwvCv6640roq8Wk/wIuaqnd4Pgtp453OyJ7hbONkQ==
629
630inflight@^1.0.4:
631 version "1.0.6"
632 resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
633 integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
634 dependencies:
635 once "^1.3.0"
636 wrappy "1"
637
638inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
639 version "2.0.3"
640 resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
641 integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
642
643ini@~1.3.0:
644 version "1.3.5"
645 resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
646 integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
647
648invert-kv@^1.0.0:
649 version "1.0.0"
650 resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
651 integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
652
653ip-set@^1.0.0:
654 version "1.0.2"
655 resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.2.tgz#be4f119f82c124836455993dfcd554639c7007de"
656 integrity sha512-Mb6kv78bTi4RNAIIWL8Bbre7hXOR2pNUi3j8FaQkLaitf/ZWxkq3/iIwXNYk2ACO3IMfdVdQrOkUtwZblO7uBA==
657 dependencies:
658 ip "^1.1.3"
659
660ip@^1.0.1, ip@^1.1.0, ip@^1.1.3:
661 version "1.1.5"
662 resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
663 integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
664
665"ipaddr.js@>= 0.1.5", ipaddr.js@^1.0.1:
666 version "1.9.0"
667 resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
668 integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
669
670is-arrayish@^0.2.1:
671 version "0.2.1"
672 resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
673 integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
674
675is-ascii@^1.0.0:
676 version "1.0.0"
677 resolved "https://registry.yarnpkg.com/is-ascii/-/is-ascii-1.0.0.tgz#f02ad0259a0921cd199ff21ce1b09e0f6b4e3929"
678 integrity sha1-8CrQJZoJIc0Zn/Ic4bCeD2tOOSk=
679
680is-file@^1.0.0:
681 version "1.0.0"
682 resolved "https://registry.yarnpkg.com/is-file/-/is-file-1.0.0.tgz#28a44cfbd9d3db193045f22b65fce8edf9620596"
683 integrity sha1-KKRM+9nT2xkwRfIrZfzo7fliBZY=
684
685is-fullwidth-code-point@^1.0.0:
686 version "1.0.0"
687 resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
688 integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
689 dependencies:
690 number-is-nan "^1.0.0"
691
692is-fullwidth-code-point@^2.0.0:
693 version "2.0.0"
694 resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
695 integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
696
697is-typedarray@^1.0.0:
698 version "1.0.0"
699 resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
700 integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
701
702is-utf8@^0.2.0:
703 version "0.2.1"
704 resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
705 integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
706
707isarray@~1.0.0:
708 version "1.0.0"
709 resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
710 integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
711
712isexe@^2.0.0:
713 version "2.0.0"
714 resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
715 integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
716
717junk@^2.1.0:
718 version "2.1.0"
719 resolved "https://registry.yarnpkg.com/junk/-/junk-2.1.0.tgz#f431b4b7f072dc500a5f10ce7f4ec71930e70134"
720 integrity sha1-9DG0t/By3FAKXxDOf07HGTDnATQ=
721
722k-bucket@^4.0.0:
723 version "4.0.1"
724 resolved "https://registry.yarnpkg.com/k-bucket/-/k-bucket-4.0.1.tgz#3fc2e5693f0b7bff90d7b6b476edd6087955d542"
725 integrity sha512-YvDpmY3waI999h1zZoW1rJ04fZrgZ+5PAlVmvwDHT6YO/Q1AOhdel07xsKy9eAvJjQ9xZV1wz3rXKqEfaWvlcQ==
726 dependencies:
727 inherits "^2.0.1"
728 randombytes "^2.0.3"
729
730k-bucket@^5.0.0:
731 version "5.0.0"
732 resolved "https://registry.yarnpkg.com/k-bucket/-/k-bucket-5.0.0.tgz#ef7a401fcd4c37cd31dceaa6ae4440ca91055e01"
733 integrity sha512-r/q+wV/Kde62/tk+rqyttEJn6h0jR7x+incdMVSYTqK73zVxVrzJa70kJL49cIKen8XjIgUZKSvk8ktnrQbK4w==
734 dependencies:
735 randombytes "^2.0.3"
736
737k-rpc-socket@^1.7.2:
738 version "1.8.0"
739 resolved "https://registry.yarnpkg.com/k-rpc-socket/-/k-rpc-socket-1.8.0.tgz#9a4dd6a4f3795ed847ffa156579cc389990bd1f2"
740 integrity sha512-f/9TynsO8YYjZ6JjNNtSSH7CJcIHcio1buy3zqByGxb/GX8AWLdL6FZEWTrN8V3/J7W4/E0ZTQQ+Jt2rVq7ELg==
741 dependencies:
742 bencode "^2.0.0"
743 buffer-equals "^1.0.4"
744 safe-buffer "^5.1.1"
745
746k-rpc@^5.0.0:
747 version "5.0.0"
748 resolved "https://registry.yarnpkg.com/k-rpc/-/k-rpc-5.0.0.tgz#a72651860c96db440579e4c9f38dce8a42b481a8"
749 integrity sha512-vCH2rQdfMOS+MlUuTSuar1pS2EMrltURf9LmAR9xR6Jik0XPlMX3vEixgqMn17wKmFVCublJqSJ4hJIP7oKZ3Q==
750 dependencies:
751 buffer-equals "^1.0.3"
752 k-bucket "^4.0.0"
753 k-rpc-socket "^1.7.2"
754 randombytes "^2.0.5"
755 safe-buffer "^5.1.1"
756
757last-one-wins@^1.0.4:
758 version "1.0.4"
759 resolved "https://registry.yarnpkg.com/last-one-wins/-/last-one-wins-1.0.4.tgz#c1bfd0cbcb46790ec9156b8d1aee8fcb86cda22a"
760 integrity sha1-wb/Qy8tGeQ7JFWuNGu6Py4bNoio=
761
762lcid@^1.0.0:
763 version "1.0.0"
764 resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
765 integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
766 dependencies:
767 invert-kv "^1.0.0"
768
769load-ip-set@^2.1.0:
770 version "2.1.0"
771 resolved "https://registry.yarnpkg.com/load-ip-set/-/load-ip-set-2.1.0.tgz#2d50b737cae41de4e413d213991d4083a3e1784b"
772 integrity sha512-taz7U6B+F7Zq90dfIKwqsB1CrFKelSEmMGC68OUqem8Cgd1QZygQBYb2Fk9i6muBSfH4xwF/Pjt4KKlAdOyWZw==
773 dependencies:
774 ip-set "^1.0.0"
775 netmask "^1.0.6"
776 once "^1.3.0"
777 simple-get "^3.0.0"
778 split "^1.0.0"
779
780load-json-file@^1.0.0:
781 version "1.1.0"
782 resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
783 integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
784 dependencies:
785 graceful-fs "^4.1.2"
786 parse-json "^2.2.0"
787 pify "^2.0.0"
788 pinkie-promise "^2.0.0"
789 strip-bom "^2.0.0"
790
791"long@~2 >=2.2.3":
792 version "2.4.0"
793 resolved "https://registry.yarnpkg.com/long/-/long-2.4.0.tgz#9fa180bb1d9500cdc29c4156766a1995e1f4524f"
794 integrity sha1-n6GAux2VAM3CnEFWdmoZleH0Uk8=
795
796lru@^3.0.0, lru@^3.1.0:
797 version "3.1.0"
798 resolved "https://registry.yarnpkg.com/lru/-/lru-3.1.0.tgz#ea7fb8546d83733396a13091d76cfeb4c06837d5"
799 integrity sha1-6n+4VG2DczOWoTCR12z+tMBoN9U=
800 dependencies:
801 inherits "^2.0.1"
802
803magnet-uri@^5.1.3:
804 version "5.2.4"
805 resolved "https://registry.yarnpkg.com/magnet-uri/-/magnet-uri-5.2.4.tgz#7afe5b736af04445aff744c93a890a3710077688"
806 integrity sha512-VYaJMxhr8B9BrCiNINUsuhaEe40YnG+AQBwcqUKO66lSVaI9I3A1iH/6EmEwRI8OYUg5Gt+4lLE7achg676lrg==
807 dependencies:
808 thirty-two "^1.0.1"
809 uniq "^1.0.1"
810
811mdns-js-packet@~0.2.0:
812 version "0.2.0"
813 resolved "https://registry.yarnpkg.com/mdns-js-packet/-/mdns-js-packet-0.2.0.tgz#642409e8183c7561cc60615bbd1420ec2fad7616"
814 integrity sha1-ZCQJ6Bg8dWHMYGFbvRQg7C+tdhY=
815 dependencies:
816 debug "^2.1.0"
817 qap "^3.1.2"
818
819mdns-js@0.5.0:
820 version "0.5.0"
821 resolved "https://registry.yarnpkg.com/mdns-js/-/mdns-js-0.5.0.tgz#4c8abb6ba7cabdc892d39228c3faa2556e09cf87"
822 integrity sha1-TIq7a6fKvciS05Iow/qiVW4Jz4c=
823 dependencies:
824 debug "^2.1.1"
825 mdns-js-packet "~0.2.0"
826 semver "~5.1.0"
827
828mediasource@^2.1.0, mediasource@^2.2.2:
829 version "2.3.0"
830 resolved "https://registry.yarnpkg.com/mediasource/-/mediasource-2.3.0.tgz#4c7b49e7ea4fb88f1cc181d8fcf0d94649271dc6"
831 integrity sha512-fqm86UwHvAnneIv40Uy1sDQaFtAByq/k0SQ3uCtbnEeSQNT1s5TDHCZOD1VmYCHwfY1jL2NjoZVwzZKYqy3L7A==
832 dependencies:
833 inherits "^2.0.1"
834 readable-stream "^3.0.0"
835 to-arraybuffer "^1.0.1"
836
837memory-chunk-store@^1.2.0:
838 version "1.3.0"
839 resolved "https://registry.yarnpkg.com/memory-chunk-store/-/memory-chunk-store-1.3.0.tgz#ae99e7e3b58b52db43d49d94722930d39459d0c4"
840 integrity sha512-6LsOpHKKhxYrLhHmOJdBCUtSO7op5rUs1pag0fhjHo0QiXRyna0bwYf4EmQuL7InUeF2J7dUMPr6VMogRyf9NA==
841
842mime@^1.3.4, mime@^1.6.0:
843 version "1.6.0"
844 resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
845 integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
846
847mime@^2.1.0, mime@^2.4.0:
848 version "2.4.3"
849 resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe"
850 integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==
851
852mimic-response@^1.0.0:
853 version "1.0.1"
854 resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
855 integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
856
857minimatch@^3.0.4:
858 version "3.0.4"
859 resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
860 integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
861 dependencies:
862 brace-expansion "^1.1.7"
863
864minimist@0.0.8:
865 version "0.0.8"
866 resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
867 integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
868
869minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0:
870 version "1.2.0"
871 resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
872 integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
873
874minipass@^2.2.1, minipass@^2.3.4:
875 version "2.3.5"
876 resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
877 integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
878 dependencies:
879 safe-buffer "^5.1.2"
880 yallist "^3.0.0"
881
882minizlib@^1.1.1:
883 version "1.2.1"
884 resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
885 integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
886 dependencies:
887 minipass "^2.2.1"
888
889mkdirp@^0.5.0, mkdirp@^0.5.1:
890 version "0.5.1"
891 resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
892 integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
893 dependencies:
894 minimist "0.0.8"
895
896moment@^2.12.0:
897 version "2.24.0"
898 resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
899 integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
900
901mp4-box-encoding@^1.1.0, mp4-box-encoding@^1.3.0:
902 version "1.3.0"
903 resolved "https://registry.yarnpkg.com/mp4-box-encoding/-/mp4-box-encoding-1.3.0.tgz#2a6f750947ff68c3a498fd76cd6424c53d995d48"
904 integrity sha512-U4pMLpjT/UzB8d36dxj6Mf1bG9xypEvgbuRIa1fztRXNKKTCAtRxsnFZhNOd7YDFOKtjBgssYGvo4H/Q3ZY1MA==
905 dependencies:
906 buffer-alloc "^1.2.0"
907 buffer-from "^1.1.0"
908 uint64be "^2.0.2"
909
910mp4-stream@^2.0.0:
911 version "2.0.3"
912 resolved "https://registry.yarnpkg.com/mp4-stream/-/mp4-stream-2.0.3.tgz#30acee07709d323f8dcd87a07b3ce9c3c4bfb364"
913 integrity sha512-5NzgI0+bGakoZEwnIYINXqB3mnewkt3Y7jcvkXsTubnCNUSdM8cpP0Vemxf6FLg0qUN8fydTgNMVAc3QU8B92g==
914 dependencies:
915 buffer-alloc "^1.1.0"
916 inherits "^2.0.1"
917 mp4-box-encoding "^1.1.0"
918 next-event "^1.0.0"
919 readable-stream "^2.0.3"
920
921ms@2.0.0:
922 version "2.0.0"
923 resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
924 integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
925
926ms@^2.1.1:
927 version "2.1.1"
928 resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
929 integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
930
931multicast-dns@^6.0.1:
932 version "6.2.3"
933 resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229"
934 integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==
935 dependencies:
936 dns-packet "^1.3.1"
937 thunky "^1.0.2"
938
939multistream@^2.0.2, multistream@^2.0.5:
940 version "2.1.1"
941 resolved "https://registry.yarnpkg.com/multistream/-/multistream-2.1.1.tgz#629d3a29bd76623489980d04519a2c365948148c"
942 integrity sha512-xasv76hl6nr1dEy3lPvy7Ej7K/Lx3O/FCvwge8PeVJpciPPoNCbaANcNiBug3IpdvTveZUcAV0DJzdnUDMesNQ==
943 dependencies:
944 inherits "^2.0.1"
945 readable-stream "^2.0.5"
946
947nan@*, nan@^2.3.2:
948 version "2.14.0"
949 resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
950 integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
951
952needle@^2.2.1:
953 version "2.4.0"
954 resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
955 integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==
956 dependencies:
957 debug "^3.2.6"
958 iconv-lite "^0.4.4"
959 sax "^1.2.4"
960
961netmask@^1.0.6:
962 version "1.0.6"
963 resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35"
964 integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=
965
966network-address@^1.0.0, network-address@^1.1.0:
967 version "1.1.2"
968 resolved "https://registry.yarnpkg.com/network-address/-/network-address-1.1.2.tgz#4aa7bfd43f03f0b81c9702b13d6a858ddb326f3e"
969 integrity sha1-Sqe/1D8D8LgclwKxPWqFjdsybz4=
970
971next-event@^1.0.0:
972 version "1.0.0"
973 resolved "https://registry.yarnpkg.com/next-event/-/next-event-1.0.0.tgz#e7778acde2e55802e0ad1879c39cf6f75eda61d8"
974 integrity sha1-53eKzeLlWALgrRh5w5z2917aYdg=
975
976node-cmake@2.3.2:
977 version "2.3.2"
978 resolved "https://registry.yarnpkg.com/node-cmake/-/node-cmake-2.3.2.tgz#e0fbc54b11405b07705e4d6d41865ae95ad289d0"
979 integrity sha1-4PvFSxFAWwdwXk1tQYZa6VrSidA=
980 dependencies:
981 nan "*"
982 which "^1.2.14"
983 yargs "^7.0.2"
984
985node-gyp-build@~3.7.0:
986 version "3.7.0"
987 resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d"
988 integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w==
989
990node-pre-gyp@0.11.x:
991 version "0.11.0"
992 resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054"
993 integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==
994 dependencies:
995 detect-libc "^1.0.2"
996 mkdirp "^0.5.1"
997 needle "^2.2.1"
998 nopt "^4.0.1"
999 npm-packlist "^1.1.6"
1000 npmlog "^4.0.2"
1001 rc "^1.2.7"
1002 rimraf "^2.6.1"
1003 semver "^5.3.0"
1004 tar "^4"
1005
1006node-ssdp@^2.2.0, node-ssdp@^2.7.1:
1007 version "2.9.1"
1008 resolved "https://registry.yarnpkg.com/node-ssdp/-/node-ssdp-2.9.1.tgz#2d6ba8e7eff9bf5b338564f91f7ac5d5cdddc55b"
1009 integrity sha1-LWuo5+/5v1szhWT5H3rF1c3dxVs=
1010 dependencies:
1011 debug "^2.2.0"
1012 ip "^1.0.1"
1013
1014nodebmc@0.0.7:
1015 version "0.0.7"
1016 resolved "https://registry.yarnpkg.com/nodebmc/-/nodebmc-0.0.7.tgz#fae179165265509302cefbebeabd29bd4035184d"
1017 integrity sha1-+uF5FlJlUJMCzvvr6r0pvUA1GE0=
1018 dependencies:
1019 mdns-js "0.5.0"
1020
1021nopt@^4.0.1:
1022 version "4.0.1"
1023 resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
1024 integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
1025 dependencies:
1026 abbrev "1"
1027 osenv "^0.1.4"
1028
1029normalize-package-data@^2.3.2:
1030 version "2.5.0"
1031 resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
1032 integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
1033 dependencies:
1034 hosted-git-info "^2.1.4"
1035 resolve "^1.10.0"
1036 semver "2 || 3 || 4 || 5"
1037 validate-npm-package-license "^3.0.1"
1038
1039npm-bundled@^1.0.1:
1040 version "1.0.6"
1041 resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd"
1042 integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
1043
1044npm-packlist@^1.1.6:
1045 version "1.4.1"
1046 resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc"
1047 integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==
1048 dependencies:
1049 ignore-walk "^3.0.1"
1050 npm-bundled "^1.0.1"
1051
1052npmlog@^4.0.2:
1053 version "4.1.2"
1054 resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
1055 integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
1056 dependencies:
1057 are-we-there-yet "~1.1.2"
1058 console-control-strings "~1.1.0"
1059 gauge "~2.7.3"
1060 set-blocking "~2.0.0"
1061
1062number-is-nan@^1.0.0:
1063 version "1.0.1"
1064 resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
1065 integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
1066
1067object-assign@^4.1.0:
1068 version "4.1.1"
1069 resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
1070 integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
1071
1072once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0:
1073 version "1.4.0"
1074 resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
1075 integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
1076 dependencies:
1077 wrappy "1"
1078
1079open@0.0.5:
1080 version "0.0.5"
1081 resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc"
1082 integrity sha1-QsPhjslUZra/DcQvOilFw/DK2Pw=
1083
1084optjs@latest:
1085 version "3.2.2"
1086 resolved "https://registry.yarnpkg.com/optjs/-/optjs-3.2.2.tgz#69a6ce89c442a44403141ad2f9b370bd5bb6f4ee"
1087 integrity sha1-aabOicRCpEQDFBrS+bNwvVu29O4=
1088
1089os-homedir@^1.0.0:
1090 version "1.0.2"
1091 resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
1092 integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
1093
1094os-locale@^1.4.0:
1095 version "1.4.0"
1096 resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
1097 integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=
1098 dependencies:
1099 lcid "^1.0.0"
1100
1101os-tmpdir@^1.0.0:
1102 version "1.0.2"
1103 resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
1104 integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
1105
1106osenv@^0.1.4:
1107 version "0.1.5"
1108 resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
1109 integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
1110 dependencies:
1111 os-homedir "^1.0.0"
1112 os-tmpdir "^1.0.0"
1113
1114package-json-versionify@^1.0.2:
1115 version "1.0.4"
1116 resolved "https://registry.yarnpkg.com/package-json-versionify/-/package-json-versionify-1.0.4.tgz#5860587a944873a6b7e6d26e8e51ffb22315bf17"
1117 integrity sha1-WGBYepRIc6a35tJujlH/siMVvxc=
1118 dependencies:
1119 browserify-package-json "^1.0.0"
1120
1121parse-json@^2.2.0:
1122 version "2.2.0"
1123 resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
1124 integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
1125 dependencies:
1126 error-ex "^1.2.0"
1127
1128parse-numeric-range@^0.0.2:
1129 version "0.0.2"
1130 resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4"
1131 integrity sha1-tPCdQTx6282Yf26SM8e0shDJOOQ=
1132
1133parse-torrent@^6.0.0, parse-torrent@^6.1.2:
1134 version "6.1.2"
1135 resolved "https://registry.yarnpkg.com/parse-torrent/-/parse-torrent-6.1.2.tgz#99da5bdd23435a1cb7e8e7a63847c4efb21b1956"
1136 integrity sha512-Z/vig84sHwtrTEbOzisT4xnYTFlOgAaLQccPruMPgRahZUppVE/BUXzAos3jZM7c64o0lfukQdQ4ozWa5lN39w==
1137 dependencies:
1138 bencode "^2.0.0"
1139 blob-to-buffer "^1.2.6"
1140 get-stdin "^6.0.0"
1141 magnet-uri "^5.1.3"
1142 simple-get "^3.0.1"
1143 simple-sha1 "^2.0.0"
1144 uniq "^1.0.1"
1145
1146path-exists@^2.0.0:
1147 version "2.1.0"
1148 resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
1149 integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
1150 dependencies:
1151 pinkie-promise "^2.0.0"
1152
1153path-is-absolute@^1.0.0:
1154 version "1.0.1"
1155 resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
1156 integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
1157
1158path-parse@^1.0.6:
1159 version "1.0.6"
1160 resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
1161 integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
1162
1163path-type@^1.0.0:
1164 version "1.1.0"
1165 resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
1166 integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
1167 dependencies:
1168 graceful-fs "^4.1.2"
1169 pify "^2.0.0"
1170 pinkie-promise "^2.0.0"
1171
1172piece-length@^1.0.0:
1173 version "1.0.0"
1174 resolved "https://registry.yarnpkg.com/piece-length/-/piece-length-1.0.0.tgz#4db7167157fd69fef14caf7262cd39f189b24508"
1175 integrity sha1-TbcWcVf9af7xTK9yYs058YmyRQg=
1176 dependencies:
1177 closest-to "~2.0.0"
1178
1179pify@^2.0.0, pify@^2.2.0:
1180 version "2.3.0"
1181 resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
1182 integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
1183
1184pinkie-promise@^2.0.0:
1185 version "2.0.1"
1186 resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
1187 integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
1188 dependencies:
1189 pinkie "^2.0.0"
1190
1191pinkie@^2.0.0:
1192 version "2.0.4"
1193 resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
1194 integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
1195
1196plist-with-patches@0.5.1:
1197 version "0.5.1"
1198 resolved "https://registry.yarnpkg.com/plist-with-patches/-/plist-with-patches-0.5.1.tgz#868aae2e0df8989b026562b35cbc19cfd8bb780d"
1199 integrity sha1-hoquLg34mJsCZWKzXLwZz9i7eA0=
1200 dependencies:
1201 xmlbuilder "0.4.x"
1202 xmldom "0.1.x"
1203
1204prettier-bytes@^1.0.3:
1205 version "1.0.4"
1206 resolved "https://registry.yarnpkg.com/prettier-bytes/-/prettier-bytes-1.0.4.tgz#994b02aa46f699c50b6257b5faaa7fe2557e62d6"
1207 integrity sha1-mUsCqkb2mcULYle1+qp/4lV+YtY=
1208
1209process-nextick-args@~2.0.0:
1210 version "2.0.0"
1211 resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
1212 integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
1213
1214protobufjs@^3.2.2:
1215 version "3.8.2"
1216 resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-3.8.2.tgz#bc826e34c3af4697e8d0af7a669e4d612aedcd17"
1217 integrity sha1-vIJuNMOvRpfo0K96Zp5NYSrtzRc=
1218 dependencies:
1219 ascli "~0.3"
1220 bytebuffer "~3 >=3.5"
1221
1222pump@^3.0.0:
1223 version "3.0.0"
1224 resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
1225 integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
1226 dependencies:
1227 end-of-stream "^1.1.0"
1228 once "^1.3.1"
1229
1230qap@^3.1.2:
1231 version "3.3.1"
1232 resolved "https://registry.yarnpkg.com/qap/-/qap-3.3.1.tgz#11f9e8fa8890fe7cb99210c0f44d0613b7372cac"
1233 integrity sha1-Efno+oiQ/ny5khDA9E0GE7c3LKw=
1234
1235random-access-file@^2.0.1:
1236 version "2.1.2"
1237 resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-2.1.2.tgz#eeb32e50b9831f32060516862381152ae4e05aa6"
1238 integrity sha512-dZo7HEcEPbZ/6XLXC4GXypiWvFbXVkdeMrJTi0B94pBJwddt/AvJh8GaQhso6KGYROGYCI/VWdHbmRDtkwT9pQ==
1239 dependencies:
1240 mkdirp "^0.5.1"
1241 random-access-storage "^1.1.1"
1242
1243random-access-storage@^1.1.1:
1244 version "1.3.0"
1245 resolved "https://registry.yarnpkg.com/random-access-storage/-/random-access-storage-1.3.0.tgz#d27e4d897b79dc4358afc2bbe553044e5c8cfe35"
1246 integrity sha512-pdS9Mcb9TB7oICypPRALlheaSuszuAKmLVEPKJMuYor7R/zDuHh5ALuQoS+ox31XRwQUL+tDwWH2GPdyspwelA==
1247 dependencies:
1248 inherits "^2.0.3"
1249
1250random-iterate@^1.0.1:
1251 version "1.0.1"
1252 resolved "https://registry.yarnpkg.com/random-iterate/-/random-iterate-1.0.1.tgz#f7d97d92dee6665ec5f6da08c7f963cad4b2ac99"
1253 integrity sha1-99l9kt7mZl7F9toIx/ljytSyrJk=
1254
1255randombytes@^2.0.3, randombytes@^2.0.5:
1256 version "2.1.0"
1257 resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
1258 integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
1259 dependencies:
1260 safe-buffer "^5.1.0"
1261
1262range-parser@^1.2.0:
1263 version "1.2.1"
1264 resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
1265 integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
1266
1267range-slice-stream@^2.0.0:
1268 version "2.0.0"
1269 resolved "https://registry.yarnpkg.com/range-slice-stream/-/range-slice-stream-2.0.0.tgz#1f25fc7a2cacf9ccd140c46f9cf670a1a7fe3ce6"
1270 integrity sha512-PPYLwZ63lXi6Tv2EZ8w3M4FzC0rVqvxivaOVS8pXSp5FMIHFnvi4MWHL3UdFLhwSy50aNtJsgjY0mBC6oFL26Q==
1271 dependencies:
1272 readable-stream "^3.0.2"
1273
1274rc@^1.2.7:
1275 version "1.2.8"
1276 resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
1277 integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
1278 dependencies:
1279 deep-extend "^0.6.0"
1280 ini "~1.3.0"
1281 minimist "^1.2.0"
1282 strip-json-comments "~2.0.1"
1283
1284read-pkg-up@^1.0.1:
1285 version "1.0.1"
1286 resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
1287 integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
1288 dependencies:
1289 find-up "^1.0.0"
1290 read-pkg "^1.0.0"
1291
1292read-pkg@^1.0.0:
1293 version "1.1.0"
1294 resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
1295 integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
1296 dependencies:
1297 load-json-file "^1.0.0"
1298 normalize-package-data "^2.3.2"
1299 path-type "^1.0.0"
1300
1301readable-stream@^2.0.3, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.3.2, readable-stream@^2.3.4:
1302 version "2.3.6"
1303 resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
1304 integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
1305 dependencies:
1306 core-util-is "~1.0.0"
1307 inherits "~2.0.3"
1308 isarray "~1.0.0"
1309 process-nextick-args "~2.0.0"
1310 safe-buffer "~5.1.1"
1311 string_decoder "~1.1.1"
1312 util-deprecate "~1.0.1"
1313
1314readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6:
1315 version "3.3.0"
1316 resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.3.0.tgz#cb8011aad002eb717bf040291feba8569c986fb9"
1317 integrity sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==
1318 dependencies:
1319 inherits "^2.0.3"
1320 string_decoder "^1.1.1"
1321 util-deprecate "^1.0.1"
1322
1323record-cache@^1.0.2:
1324 version "1.1.0"
1325 resolved "https://registry.yarnpkg.com/record-cache/-/record-cache-1.1.0.tgz#f8a467a691a469584b26e88d36b18afdb3932037"
1326 integrity sha512-u8rbtLEJV7HRacl/ZYwSBFD8NFyB3PfTTfGLP37IW3hftQCwu6z4Q2RLyxo1YJUNRTEzJfpLpGwVuEYdaIkG9Q==
1327
1328render-media@^3.0.0:
1329 version "3.1.3"
1330 resolved "https://registry.yarnpkg.com/render-media/-/render-media-3.1.3.tgz#aa8c8cd3f720049370067180709b551d3c566254"
1331 integrity sha512-K7ziKKlIcgYpAovRsABDiSaNn7TzDDyyuFGpRwM52cloNcajInB6sCxFPUEzOuTJUeyvKCqT/k5INOjpKLCjhQ==
1332 dependencies:
1333 debug "^3.1.0"
1334 is-ascii "^1.0.0"
1335 mediasource "^2.1.0"
1336 stream-to-blob-url "^2.0.0"
1337 videostream "^2.5.1"
1338
1339require-directory@^2.1.1:
1340 version "2.1.1"
1341 resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
1342 integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
1343
1344require-main-filename@^1.0.1:
1345 version "1.0.1"
1346 resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
1347 integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
1348
1349resolve@^1.10.0:
1350 version "1.11.0"
1351 resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.0.tgz#4014870ba296176b86343d50b60f3b50609ce232"
1352 integrity sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==
1353 dependencies:
1354 path-parse "^1.0.6"
1355
1356rimraf@^2.4.2, rimraf@^2.6.1:
1357 version "2.6.3"
1358 resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
1359 integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
1360 dependencies:
1361 glob "^7.1.3"
1362
1363run-parallel-limit@^1.0.3:
1364 version "1.0.5"
1365 resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.0.5.tgz#c29a4fd17b4df358cb52a8a697811a63c984f1b7"
1366 integrity sha512-NsY+oDngvrvMxKB3G8ijBzIema6aYbQMD2bHOamvN52BysbIGTnEY2xsNyfrcr9GhY995/t/0nQN3R3oZvaDlg==
1367
1368run-parallel@^1.0.0, run-parallel@^1.1.2, run-parallel@^1.1.6:
1369 version "1.1.9"
1370 resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
1371 integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
1372
1373run-series@^1.0.2:
1374 version "1.1.8"
1375 resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36"
1376 integrity sha512-+GztYEPRpIsQoCSraWHDBs9WVy4eVME16zhOtDB4H9J4xN0XRhknnmLOl+4gRgZtu8dpp9N/utSPjKH/xmDzXg==
1377
1378rusha@^0.8.1:
1379 version "0.8.13"
1380 resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.13.tgz#9a084e7b860b17bff3015b92c67a6a336191513a"
1381 integrity sha1-mghOe4YLF7/zAVuSxnpqM2GRUTo=
1382
1383safe-buffer@^5.0.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
1384 version "5.1.2"
1385 resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
1386 integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
1387
1388"safer-buffer@>= 2.1.2 < 3":
1389 version "2.1.2"
1390 resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
1391 integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
1392
1393sax@1.1.4:
1394 version "1.1.4"
1395 resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.4.tgz#74b6d33c9ae1e001510f179a91168588f1aedaa9"
1396 integrity sha1-dLbTPJrh4AFRDxeakRaFiPGu2qk=
1397
1398sax@>=0.6.0, sax@^1.2.4:
1399 version "1.2.4"
1400 resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
1401 integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
1402
1403"semver@2 || 3 || 4 || 5", semver@^5.3.0:
1404 version "5.7.0"
1405 resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
1406 integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
1407
1408semver@~5.1.0:
1409 version "5.1.1"
1410 resolved "https://registry.yarnpkg.com/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19"
1411 integrity sha1-oykqNz5vPgeY2gsgZBuanFvEfhk=
1412
1413set-blocking@^2.0.0, set-blocking@~2.0.0:
1414 version "2.0.0"
1415 resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
1416 integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
1417
1418signal-exit@^3.0.0:
1419 version "3.0.2"
1420 resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
1421 integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
1422
1423simple-concat@^1.0.0:
1424 version "1.0.0"
1425 resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6"
1426 integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=
1427
1428simple-get@^2.0.0, simple-get@^2.1.0:
1429 version "2.8.1"
1430 resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d"
1431 integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==
1432 dependencies:
1433 decompress-response "^3.3.0"
1434 once "^1.3.1"
1435 simple-concat "^1.0.0"
1436
1437simple-get@^3.0.0, simple-get@^3.0.1:
1438 version "3.0.3"
1439 resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.0.3.tgz#924528ac3f9d7718ce5e9ec1b1a69c0be4d62efa"
1440 integrity sha512-Wvre/Jq5vgoz31Z9stYWPLn0PqRqmBDpFSdypAnHu5AvRVCYPRYGnvryNLiXu8GOBNDH82J2FRHUGMjjHUpXFw==
1441 dependencies:
1442 decompress-response "^3.3.0"
1443 once "^1.3.1"
1444 simple-concat "^1.0.0"
1445
1446simple-peer@^9.0.0:
1447 version "9.3.0"
1448 resolved "https://registry.yarnpkg.com/simple-peer/-/simple-peer-9.3.0.tgz#85ecb126b23d8730f3904f199db65e84141e0f4e"
1449 integrity sha512-5dLDfrRomrS2LuZUuH2aO7yTGtHFEl5Eb+8ZzqM0KC0lHcYUyJudUomP9ZY/lPUKBx2broL/Eee9bQ53yycEgQ==
1450 dependencies:
1451 debug "^4.0.1"
1452 get-browser-rtc "^1.0.0"
1453 inherits "^2.0.1"
1454 randombytes "^2.0.3"
1455 readable-stream "^2.3.4"
1456
1457simple-sha1@^2.0.0, simple-sha1@^2.0.8, simple-sha1@^2.1.0:
1458 version "2.1.2"
1459 resolved "https://registry.yarnpkg.com/simple-sha1/-/simple-sha1-2.1.2.tgz#de40cbd5aae278fde8e3bb3250a35d74c67326b1"
1460 integrity sha512-TQl9rm4rdKAVmhO++sXAb8TNN0D6JAD5iyI1mqEPNpxUzTRrtm4aOG1pDf/5W/qCFihiaoK6uuL9rvQz1x1VKw==
1461 dependencies:
1462 rusha "^0.8.1"
1463
1464simple-websocket@^7.0.1:
1465 version "7.2.0"
1466 resolved "https://registry.yarnpkg.com/simple-websocket/-/simple-websocket-7.2.0.tgz#c3190555d74399372b96b51435f2d8c4b04611df"
1467 integrity sha512-wdxFg1fHw1yqFKWDcw+yNb4VIYqtl+vknZMlpLhvZSlR6l7/iVuwozqo+Qtl73mB1IH5QnXzonD1S+hAaLNTvQ==
1468 dependencies:
1469 debug "^3.1.0"
1470 inherits "^2.0.1"
1471 randombytes "^2.0.3"
1472 readable-stream "^2.0.5"
1473 ws "^6.0.0"
1474
1475spdx-correct@^3.0.0:
1476 version "3.1.0"
1477 resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
1478 integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==
1479 dependencies:
1480 spdx-expression-parse "^3.0.0"
1481 spdx-license-ids "^3.0.0"
1482
1483spdx-exceptions@^2.1.0:
1484 version "2.2.0"
1485 resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
1486 integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
1487
1488spdx-expression-parse@^3.0.0:
1489 version "3.0.0"
1490 resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
1491 integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
1492 dependencies:
1493 spdx-exceptions "^2.1.0"
1494 spdx-license-ids "^3.0.0"
1495
1496spdx-license-ids@^3.0.0:
1497 version "3.0.4"
1498 resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1"
1499 integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==
1500
1501speedometer@^1.0.0:
1502 version "1.1.0"
1503 resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.1.0.tgz#a30b13abda45687a1a76977012c060f2ac8a7934"
1504 integrity sha512-z/wAiTESw2XVPssY2XRcme4niTc4S5FkkJ4gknudtVoc33Zil8TdTxHy5torRcgqMqksJV2Yz8HQcvtbsnw0mQ==
1505
1506split@^1.0.0:
1507 version "1.0.1"
1508 resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9"
1509 integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==
1510 dependencies:
1511 through "2"
1512
1513stream-to-blob-url@^2.0.0, stream-to-blob-url@^2.1.0:
1514 version "2.1.1"
1515 resolved "https://registry.yarnpkg.com/stream-to-blob-url/-/stream-to-blob-url-2.1.1.tgz#e1ac97f86ca8e9f512329a48e7830ce9a50beef2"
1516 integrity sha512-DKJPEmCmIZoBfGVle9IhSfERiWaN5cuOtmfPxP2dZbLDRZxkBWZ4QbYxEJOSALk1Kf+WjBgedAMO6qkkf7Lmrg==
1517 dependencies:
1518 stream-to-blob "^1.0.0"
1519
1520stream-to-blob@^1.0.0:
1521 version "1.0.1"
1522 resolved "https://registry.yarnpkg.com/stream-to-blob/-/stream-to-blob-1.0.1.tgz#2dc1e09b71677a234d00445f8eb7ff70c4fe9948"
1523 integrity sha512-aRy4neA4rf+qMtLT9fCRLPGWdrsIKtCx4kUdNTIPgPQ2hkHkdxbViVAvABMx9oRM6yCWfngHx6pwXfbYkVuPuw==
1524 dependencies:
1525 once "^1.3.3"
1526
1527stream-with-known-length-to-buffer@^1.0.0:
1528 version "1.0.2"
1529 resolved "https://registry.yarnpkg.com/stream-with-known-length-to-buffer/-/stream-with-known-length-to-buffer-1.0.2.tgz#b8ea5a92086a1ed5d27fc4c529636682118c945b"
1530 integrity sha512-UxSISjxmguvfYzZdq6d4XAjc3gAocqTIOS1CjgwkDkkGT/LMTsIYiV8agIw42IHFFHf8k4lPOoroCCf4W9oqzg==
1531 dependencies:
1532 once "^1.3.3"
1533
1534string-width@^1.0.1, string-width@^1.0.2:
1535 version "1.0.2"
1536 resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
1537 integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
1538 dependencies:
1539 code-point-at "^1.0.0"
1540 is-fullwidth-code-point "^1.0.0"
1541 strip-ansi "^3.0.0"
1542
1543"string-width@^1.0.2 || 2":
1544 version "2.1.1"
1545 resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
1546 integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
1547 dependencies:
1548 is-fullwidth-code-point "^2.0.0"
1549 strip-ansi "^4.0.0"
1550
1551string2compact@^1.1.1, string2compact@^1.2.5:
1552 version "1.3.0"
1553 resolved "https://registry.yarnpkg.com/string2compact/-/string2compact-1.3.0.tgz#22d946127b082d1203c51316af60117a337423c3"
1554 integrity sha512-004ulKKANDuQilQsNxy2lisrpMG0qUJxBU+2YCEF7KziRyNR0Nredm2qk0f1V82nva59H3y9GWeHXE63HzGRFw==
1555 dependencies:
1556 addr-to-ip-port "^1.0.1"
1557 ipaddr.js "^1.0.1"
1558
1559string_decoder@^1.1.1:
1560 version "1.2.0"
1561 resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
1562 integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
1563 dependencies:
1564 safe-buffer "~5.1.0"
1565
1566string_decoder@~1.1.1:
1567 version "1.1.1"
1568 resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
1569 integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
1570 dependencies:
1571 safe-buffer "~5.1.0"
1572
1573strip-ansi@^3.0.0, strip-ansi@^3.0.1:
1574 version "3.0.1"
1575 resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
1576 integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
1577 dependencies:
1578 ansi-regex "^2.0.0"
1579
1580strip-ansi@^4.0.0:
1581 version "4.0.0"
1582 resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
1583 integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
1584 dependencies:
1585 ansi-regex "^3.0.0"
1586
1587strip-bom@^2.0.0:
1588 version "2.0.0"
1589 resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
1590 integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
1591 dependencies:
1592 is-utf8 "^0.2.0"
1593
1594strip-json-comments@~2.0.1:
1595 version "2.0.1"
1596 resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
1597 integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
1598
1599tar@^4:
1600 version "4.4.8"
1601 resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
1602 integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==
1603 dependencies:
1604 chownr "^1.1.1"
1605 fs-minipass "^1.2.5"
1606 minipass "^2.3.4"
1607 minizlib "^1.1.1"
1608 mkdirp "^0.5.0"
1609 safe-buffer "^5.1.2"
1610 yallist "^3.0.2"
1611
1612thirty-two@^1.0.1:
1613 version "1.0.2"
1614 resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a"
1615 integrity sha1-TKL//AKlEpDSdEueP1V2k8prYno=
1616
1617through@2:
1618 version "2.3.8"
1619 resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
1620 integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
1621
1622thunky@^0.1.0:
1623 version "0.1.0"
1624 resolved "https://registry.yarnpkg.com/thunky/-/thunky-0.1.0.tgz#bf30146824e2b6e67b0f2d7a4ac8beb26908684e"
1625 integrity sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=
1626
1627thunky@^1.0.1, thunky@^1.0.2:
1628 version "1.0.3"
1629 resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826"
1630 integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==
1631
1632to-arraybuffer@^1.0.1:
1633 version "1.0.1"
1634 resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
1635 integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
1636
1637torrent-discovery@^9.1.1:
1638 version "9.1.1"
1639 resolved "https://registry.yarnpkg.com/torrent-discovery/-/torrent-discovery-9.1.1.tgz#56704e6747b24fe00dbb75b442d202051f78d37d"
1640 integrity sha512-3mHf+bxVCVLrlkPJdAoMbPMY1hpTZVeWw5hNc2pPFm+HCc2DS0HgVFTBTSWtB8vQPWA1hSEZpqJ+3QfdXxDE1g==
1641 dependencies:
1642 bittorrent-dht "^9.0.0"
1643 bittorrent-tracker "^9.0.0"
1644 debug "^3.1.0"
1645 run-parallel "^1.1.2"
1646
1647torrent-piece@^2.0.0:
1648 version "2.0.0"
1649 resolved "https://registry.yarnpkg.com/torrent-piece/-/torrent-piece-2.0.0.tgz#6598ae67d93699e887f178db267ba16d89d7ec9b"
1650 integrity sha512-H/Z/yCuvZJj1vl1IQHI8dvF2QrUuXRJoptT5DW5967/dsLpXlCg+uyhFR5lfNj5mNaYePUbKtnL+qKWZGXv4Nw==
1651
1652typedarray-to-buffer@^3.0.0:
1653 version "3.1.5"
1654 resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
1655 integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
1656 dependencies:
1657 is-typedarray "^1.0.0"
1658
1659typedarray@^0.0.6:
1660 version "0.0.6"
1661 resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
1662 integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
1663
1664uint64be@^2.0.2:
1665 version "2.0.2"
1666 resolved "https://registry.yarnpkg.com/uint64be/-/uint64be-2.0.2.tgz#ef4a179752fe8f9ddaa29544ecfc13490031e8e5"
1667 integrity sha512-9QqdvpGQTXgxthP+lY4e/gIBy+RuqcBaC6JVwT5I3bDLgT/btL6twZMR0pI3/Fgah9G/pdwzIprE5gL6v9UvyQ==
1668 dependencies:
1669 buffer-alloc "^1.1.0"
1670
1671uniq@^1.0.1:
1672 version "1.0.1"
1673 resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
1674 integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=
1675
1676unordered-array-remove@^1.0.2:
1677 version "1.0.2"
1678 resolved "https://registry.yarnpkg.com/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz#c546e8f88e317a0cf2644c97ecb57dba66d250ef"
1679 integrity sha1-xUbo+I4xegzyZEyX7LV9umbSUO8=
1680
1681upnp-device-client@^1.0.0:
1682 version "1.0.2"
1683 resolved "https://registry.yarnpkg.com/upnp-device-client/-/upnp-device-client-1.0.2.tgz#91f84705f2349bf89082855fff4e3006ac435337"
1684 integrity sha1-kfhHBfI0m/iQgoVf/04wBqxDUzc=
1685 dependencies:
1686 concat-stream "^1.4.8"
1687 debug "^2.1.3"
1688 elementtree "~0.1.6"
1689 network-address "^1.0.0"
1690
1691upnp-mediarenderer-client@^1.2.2:
1692 version "1.2.4"
1693 resolved "https://registry.yarnpkg.com/upnp-mediarenderer-client/-/upnp-mediarenderer-client-1.2.4.tgz#0c63a51802082b6b03b596c475cc64fc1e0877c8"
1694 integrity sha1-DGOlGAIIK2sDtZbEdcxk/B4Id8g=
1695 dependencies:
1696 debug "^2.1.3"
1697 elementtree "^0.1.6"
1698 upnp-device-client "^1.0.0"
1699
1700url-join@^2.0.5:
1701 version "2.0.5"
1702 resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728"
1703 integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=
1704
1705ut_metadata@^3.3.0:
1706 version "3.3.0"
1707 resolved "https://registry.yarnpkg.com/ut_metadata/-/ut_metadata-3.3.0.tgz#a0e0e861ebc39ed96e506601d1463ade3b548a7e"
1708 integrity sha512-IK+ke9yL6a4oPLz/3oSW9TW7m9Wr4RG+5kW5aS2YulzEU1QDGAtago/NnOlno91fo3fSO7mnsqzn3NXNXdv8nA==
1709 dependencies:
1710 bencode "^2.0.0"
1711 bitfield "^2.0.0"
1712 debug "^3.1.0"
1713 simple-sha1 "^2.0.0"
1714
1715ut_pex@^1.1.1:
1716 version "1.2.1"
1717 resolved "https://registry.yarnpkg.com/ut_pex/-/ut_pex-1.2.1.tgz#472ed0ea5e9bbc9148b833339d56d7b17cf3dad0"
1718 integrity sha512-ZrxMCbffYtxQDqvREN9kBXK2CB9tPnd5PylHoqQX9ai+3HV9/S39FnA5JnhLOC82dxIQQg0nTN2wmhtAdGNtOA==
1719 dependencies:
1720 bencode "^2.0.0"
1721 compact2string "^1.2.0"
1722 inherits "^2.0.1"
1723 string2compact "^1.2.5"
1724
1725utf-8-validate@^5.0.1:
1726 version "5.0.2"
1727 resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.2.tgz#63cfbccd85dc1f2b66cf7a1d0eebc08ed056bfb3"
1728 integrity sha512-SwV++i2gTD5qh2XqaPzBnNX88N6HdyhQrNNRykvcS0QKvItV9u3vPEJr+X5Hhfb1JC0r0e1alL0iB09rY8+nmw==
1729 dependencies:
1730 node-gyp-build "~3.7.0"
1731
1732util-deprecate@^1.0.1, util-deprecate@~1.0.1:
1733 version "1.0.2"
1734 resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
1735 integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
1736
1737validate-npm-package-license@^3.0.1:
1738 version "3.0.4"
1739 resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
1740 integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
1741 dependencies:
1742 spdx-correct "^3.0.0"
1743 spdx-expression-parse "^3.0.0"
1744
1745videostream@^2.5.1:
1746 version "2.6.0"
1747 resolved "https://registry.yarnpkg.com/videostream/-/videostream-2.6.0.tgz#7f0b2b84bc457c12cfe599aa2345f5cc06241ab6"
1748 integrity sha512-nSsullx1BYClJxVSt4Fa+Ulsv0Cf7UwaHq+4LQdLkAUdmqNhY1DlGxXDWVY2gui5XV4FvDiSbXmSbGryMrrUCQ==
1749 dependencies:
1750 binary-search "^1.3.4"
1751 inherits "^2.0.1"
1752 mediasource "^2.2.2"
1753 mp4-box-encoding "^1.3.0"
1754 mp4-stream "^2.0.0"
1755 multistream "^2.0.2"
1756 pump "^3.0.0"
1757 range-slice-stream "^2.0.0"
1758
1759vlc-command@^1.0.0:
1760 version "1.1.2"
1761 resolved "https://registry.yarnpkg.com/vlc-command/-/vlc-command-1.1.2.tgz#61a9b4249a0001c0bcac8cdaf36d3a8e674cffce"
1762 integrity sha512-KZ15RTHz96OEiQDA8oNFn1edYDWyKJIWI4gF74Am9woZo5XmVYryk5RYXSwOMvsaAgL5ejICEGCl0suQyDBu+Q==
1763 dependencies:
1764 run-parallel "^1.1.6"
1765 winreg "^1.2.1"
1766
1767webidl-conversions@^4.0.2:
1768 version "4.0.2"
1769 resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
1770 integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
1771
1772webtorrent-cli@^1.12.3:
1773 version "1.12.3"
1774 resolved "https://registry.yarnpkg.com/webtorrent-cli/-/webtorrent-cli-1.12.3.tgz#e6a1060cd3f104346da91e67763276ca897f238c"
1775 integrity sha512-NnBAGkD64CRsl9edM9q0QU+ku6nCX32nM0U+YC8Gs/36c8y+5m9Tya3mWIux3oZKZ54yGiVtnok4tUpqDE5tMA==
1776 dependencies:
1777 clivas "^0.2.0"
1778 create-torrent "^3.23.1"
1779 dlnacasts "^0.1.0"
1780 ecstatic "^3.0.0"
1781 executable "^4.0.0"
1782 mime "^2.1.0"
1783 minimist "^1.2.0"
1784 moment "^2.12.0"
1785 network-address "^1.1.0"
1786 open "0.0.5"
1787 parse-torrent "^6.0.0"
1788 prettier-bytes "^1.0.3"
1789 vlc-command "^1.0.0"
1790 webtorrent "0.x"
1791 winreg "^1.0.1"
1792 optionalDependencies:
1793 airplay-js "^0.3.0"
1794 chromecasts "^1.5.3"
1795 nodebmc "0.0.7"
1796
1797webtorrent-hybrid@^2.1.0:
1798 version "2.1.0"
1799 resolved "https://registry.yarnpkg.com/webtorrent-hybrid/-/webtorrent-hybrid-2.1.0.tgz#c14d33d6769667d8ae524ca2d9dfdcd18d4cfbf2"
1800 integrity sha512-S8tUgUbPLwGazPrBMTqjsuxlmhaCZaiC+KlgS7ECRGaHVVZTJjKG2kUw8uf558DdZbsEA3jNxOOsMvXiA62sFw==
1801 dependencies:
1802 create-torrent "^3.33.0"
1803 webtorrent "^0.x"
1804 webtorrent-cli "^1.12.3"
1805 wrtc "^0.3.3"
1806
1807webtorrent@0.x, webtorrent@^0.x:
1808 version "0.103.1"
1809 resolved "https://registry.yarnpkg.com/webtorrent/-/webtorrent-0.103.1.tgz#18ead369bbcaa60dc8ea138784c33451edd34479"
1810 integrity sha512-rqMD8sAaPzrUzEpA6gDEOgcN9Xyz4WGrQiHoVY6HlymLoNSkScMnmnEX1bsdMcIU9iOrnUlghDEW9sJ9jYCmwQ==
1811 dependencies:
1812 addr-to-ip-port "^1.4.2"
1813 bitfield "^2.0.0"
1814 bittorrent-dht "^9.0.0"
1815 bittorrent-protocol "^3.0.0"
1816 chunk-store-stream "^3.0.1"
1817 create-torrent "^3.33.0"
1818 debug "^4.1.0"
1819 end-of-stream "^1.1.0"
1820 fs-chunk-store "^1.6.2"
1821 immediate-chunk-store "^2.0.0"
1822 load-ip-set "^2.1.0"
1823 memory-chunk-store "^1.2.0"
1824 mime "^2.4.0"
1825 multistream "^2.0.5"
1826 package-json-versionify "^1.0.2"
1827 parse-numeric-range "^0.0.2"
1828 parse-torrent "^6.1.2"
1829 pump "^3.0.0"
1830 random-iterate "^1.0.1"
1831 randombytes "^2.0.3"
1832 range-parser "^1.2.0"
1833 readable-stream "^3.0.6"
1834 render-media "^3.0.0"
1835 run-parallel "^1.1.6"
1836 run-parallel-limit "^1.0.3"
1837 safe-buffer "^5.0.1"
1838 simple-concat "^1.0.0"
1839 simple-get "^3.0.1"
1840 simple-peer "^9.0.0"
1841 simple-sha1 "^2.0.8"
1842 speedometer "^1.0.0"
1843 stream-to-blob "^1.0.0"
1844 stream-to-blob-url "^2.1.0"
1845 stream-with-known-length-to-buffer "^1.0.0"
1846 torrent-discovery "^9.1.1"
1847 torrent-piece "^2.0.0"
1848 uniq "^1.0.1"
1849 unordered-array-remove "^1.0.2"
1850 ut_metadata "^3.3.0"
1851 ut_pex "^1.1.1"
1852
1853which-module@^1.0.0:
1854 version "1.0.0"
1855 resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
1856 integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
1857
1858which@^1.2.14:
1859 version "1.3.1"
1860 resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
1861 integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
1862 dependencies:
1863 isexe "^2.0.0"
1864
1865wide-align@^1.1.0:
1866 version "1.1.3"
1867 resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
1868 integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
1869 dependencies:
1870 string-width "^1.0.2 || 2"
1871
1872winreg@^1.0.1, winreg@^1.2.1:
1873 version "1.2.4"
1874 resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b"
1875 integrity sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs=
1876
1877wrap-ansi@^2.0.0:
1878 version "2.1.0"
1879 resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
1880 integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
1881 dependencies:
1882 string-width "^1.0.1"
1883 strip-ansi "^3.0.1"
1884
1885wrappy@1:
1886 version "1.0.2"
1887 resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
1888 integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
1889
1890wrtc@^0.3.3:
1891 version "0.3.7"
1892 resolved "https://registry.yarnpkg.com/wrtc/-/wrtc-0.3.7.tgz#2279f1cb3a83573e77b3d9b7e720071fab2ae4af"
1893 integrity sha512-mDFNFqAB+3IYVKlP15vpGD0EhXjsQlj/GLNje4KLpClLSq8pyTG0xqJFoU+Oq43XvDIUMmIJ/r1aNfrjT7KUQw==
1894 dependencies:
1895 nan "^2.3.2"
1896 node-cmake "2.3.2"
1897 node-pre-gyp "0.11.x"
1898 optionalDependencies:
1899 domexception "^1.0.1"
1900
1901ws@^6.0.0:
1902 version "6.2.1"
1903 resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
1904 integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==
1905 dependencies:
1906 async-limiter "~1.0.0"
1907
1908xml2js@^0.4.8:
1909 version "0.4.19"
1910 resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"
1911 integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==
1912 dependencies:
1913 sax ">=0.6.0"
1914 xmlbuilder "~9.0.1"
1915
1916xmlbuilder@0.4.x:
1917 version "0.4.3"
1918 resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-0.4.3.tgz#c4614ba74e0ad196e609c9272cd9e1ddb28a8a58"
1919 integrity sha1-xGFLp04K0ZbmCcknLNnh3bKKilg=
1920
1921xmlbuilder@~9.0.1:
1922 version "9.0.7"
1923 resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
1924 integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=
1925
1926xmldom@0.1.x:
1927 version "0.1.27"
1928 resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
1929 integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk=
1930
1931xtend@^4.0.0, xtend@^4.0.1:
1932 version "4.0.1"
1933 resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
1934 integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
1935
1936y18n@^3.2.1:
1937 version "3.2.1"
1938 resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
1939 integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
1940
1941yallist@^3.0.0, yallist@^3.0.2:
1942 version "3.0.3"
1943 resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
1944 integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
1945
1946yargs-parser@^5.0.0:
1947 version "5.0.0"
1948 resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
1949 integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=
1950 dependencies:
1951 camelcase "^3.0.0"
1952
1953yargs@^7.0.2:
1954 version "7.1.0"
1955 resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
1956 integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=
1957 dependencies:
1958 camelcase "^3.0.0"
1959 cliui "^3.2.0"
1960 decamelize "^1.1.1"
1961 get-caller-file "^1.0.1"
1962 os-locale "^1.4.0"
1963 read-pkg-up "^1.0.1"
1964 require-directory "^2.1.1"
1965 require-main-filename "^1.0.1"
1966 set-blocking "^2.0.0"
1967 string-width "^1.0.2"
1968 which-module "^1.0.0"
1969 y18n "^3.2.1"
1970 yargs-parser "^5.0.0"
diff --git a/shared/core-utils/miscs/date.ts b/shared/core-utils/miscs/date.ts
new file mode 100644
index 000000000..4f92f758f
--- /dev/null
+++ b/shared/core-utils/miscs/date.ts
@@ -0,0 +1,67 @@
1function isToday (d: Date) {
2 const today = new Date()
3
4 return areDatesEqual(d, today)
5}
6
7function isYesterday (d: Date) {
8 const yesterday = new Date()
9 yesterday.setDate(yesterday.getDate() - 1)
10
11 return areDatesEqual(d, yesterday)
12}
13
14function isThisWeek (d: Date) {
15 const minDateOfThisWeek = new Date()
16 minDateOfThisWeek.setHours(0, 0, 0)
17
18 // getDay() -> Sunday - Saturday : 0 - 6
19 // We want to start our week on Monday
20 let dayOfWeek = minDateOfThisWeek.getDay() - 1
21 if (dayOfWeek < 0) dayOfWeek = 6 // Sunday
22
23 minDateOfThisWeek.setDate(minDateOfThisWeek.getDate() - dayOfWeek)
24
25 return d >= minDateOfThisWeek
26}
27
28function isThisMonth (d: Date) {
29 const thisMonth = new Date().getMonth()
30
31 return d.getMonth() === thisMonth
32}
33
34function isLastMonth (d: Date) {
35 const now = new Date()
36
37 return getDaysDifferences(now, d) <= 30
38}
39
40function isLastWeek (d: Date) {
41 const now = new Date()
42
43 return getDaysDifferences(now, d) <= 7
44}
45
46// ---------------------------------------------------------------------------
47
48export {
49 isYesterday,
50 isThisWeek,
51 isThisMonth,
52 isToday,
53 isLastMonth,
54 isLastWeek
55}
56
57// ---------------------------------------------------------------------------
58
59function areDatesEqual (d1: Date, d2: Date) {
60 return d1.getFullYear() === d2.getFullYear() &&
61 d1.getMonth() === d2.getMonth() &&
62 d1.getDate() === d2.getDate()
63}
64
65function getDaysDifferences (d1: Date, d2: Date) {
66 return (d1.getTime() - d2.getTime()) / (86400000)
67}
diff --git a/shared/extra-utils/miscs/sql.ts b/shared/extra-utils/miscs/sql.ts
index 3cfae5c23..34477cb78 100644
--- a/shared/extra-utils/miscs/sql.ts
+++ b/shared/extra-utils/miscs/sql.ts
@@ -1,11 +1,12 @@
1import { QueryTypes, Sequelize } from 'sequelize' 1import { QueryTypes, Sequelize } from 'sequelize'
2import { ServerInfo } from '../server/servers'
2 3
3let sequelizes: { [ id: number ]: Sequelize } = {} 4let sequelizes: { [ id: number ]: Sequelize } = {}
4 5
5function getSequelize (serverNumber: number) { 6function getSequelize (internalServerNumber: number) {
6 if (sequelizes[serverNumber]) return sequelizes[serverNumber] 7 if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber]
7 8
8 const dbname = 'peertube_test' + serverNumber 9 const dbname = 'peertube_test' + internalServerNumber
9 const username = 'peertube' 10 const username = 'peertube'
10 const password = 'peertube' 11 const password = 'peertube'
11 const host = 'localhost' 12 const host = 'localhost'
@@ -18,37 +19,37 @@ function getSequelize (serverNumber: number) {
18 logging: false 19 logging: false
19 }) 20 })
20 21
21 sequelizes[serverNumber] = seq 22 sequelizes[internalServerNumber] = seq
22 23
23 return seq 24 return seq
24} 25}
25 26
26function setActorField (serverNumber: number, to: string, field: string, value: string) { 27function setActorField (internalServerNumber: number, to: string, field: string, value: string) {
27 const seq = getSequelize(serverNumber) 28 const seq = getSequelize(internalServerNumber)
28 29
29 const options = { type: QueryTypes.UPDATE } 30 const options = { type: QueryTypes.UPDATE }
30 31
31 return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options) 32 return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options)
32} 33}
33 34
34function setVideoField (serverNumber: number, uuid: string, field: string, value: string) { 35function setVideoField (internalServerNumber: number, uuid: string, field: string, value: string) {
35 const seq = getSequelize(serverNumber) 36 const seq = getSequelize(internalServerNumber)
36 37
37 const options = { type: QueryTypes.UPDATE } 38 const options = { type: QueryTypes.UPDATE }
38 39
39 return seq.query(`UPDATE video SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options) 40 return seq.query(`UPDATE video SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
40} 41}
41 42
42function setPlaylistField (serverNumber: number, uuid: string, field: string, value: string) { 43function setPlaylistField (internalServerNumber: number, uuid: string, field: string, value: string) {
43 const seq = getSequelize(serverNumber) 44 const seq = getSequelize(internalServerNumber)
44 45
45 const options = { type: QueryTypes.UPDATE } 46 const options = { type: QueryTypes.UPDATE }
46 47
47 return seq.query(`UPDATE "videoPlaylist" SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options) 48 return seq.query(`UPDATE "videoPlaylist" SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
48} 49}
49 50
50async function countVideoViewsOf (serverNumber: number, uuid: string) { 51async function countVideoViewsOf (internalServerNumber: number, uuid: string) {
51 const seq = getSequelize(serverNumber) 52 const seq = getSequelize(internalServerNumber)
52 53
53 // tslint:disable 54 // tslint:disable
54 const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'` 55 const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'`
@@ -62,11 +63,11 @@ async function countVideoViewsOf (serverNumber: number, uuid: string) {
62 return parseInt(total + '', 10) 63 return parseInt(total + '', 10)
63} 64}
64 65
65async function closeAllSequelize (servers: any[]) { 66async function closeAllSequelize (servers: ServerInfo[]) {
66 for (let i = 1; i <= servers.length; i++) { 67 for (const server of servers) {
67 if (sequelizes[ i ]) { 68 if (sequelizes[ server.internalServerNumber ]) {
68 await sequelizes[ i ].close() 69 await sequelizes[ server.internalServerNumber ].close()
69 delete sequelizes[ i ] 70 delete sequelizes[ server.internalServerNumber ]
70 } 71 }
71 } 72 }
72} 73}
diff --git a/shared/extra-utils/search/videos.ts b/shared/extra-utils/search/videos.ts
index ba4627017..5cf8d8cf0 100644
--- a/shared/extra-utils/search/videos.ts
+++ b/shared/extra-utils/search/videos.ts
@@ -6,9 +6,11 @@ import { immutableAssign } from '../miscs/miscs'
6 6
7function searchVideo (url: string, search: string) { 7function searchVideo (url: string, search: string) {
8 const path = '/api/v1/search/videos' 8 const path = '/api/v1/search/videos'
9
10 const query = { sort: '-publishedAt', search: search }
9 const req = request(url) 11 const req = request(url)
10 .get(path) 12 .get(path)
11 .query({ sort: '-publishedAt', search }) 13 .query(query)
12 .set('Accept', 'application/json') 14 .set('Accept', 'application/json')
13 15
14 return req.expect(200) 16 return req.expect(200)
@@ -30,11 +32,15 @@ function searchVideoWithToken (url: string, search: string, token: string, query
30function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) { 32function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) {
31 const path = '/api/v1/search/videos' 33 const path = '/api/v1/search/videos'
32 34
35 const query = {
36 start,
37 search,
38 count
39 }
40
33 const req = request(url) 41 const req = request(url)
34 .get(path) 42 .get(path)
35 .query({ start }) 43 .query(query)
36 .query({ search })
37 .query({ count })
38 44
39 if (sort) req.query({ sort }) 45 if (sort) req.query({ sort })
40 46
@@ -46,10 +52,11 @@ function searchVideoWithPagination (url: string, search: string, start: number,
46function searchVideoWithSort (url: string, search: string, sort: string) { 52function searchVideoWithSort (url: string, search: string, sort: string) {
47 const path = '/api/v1/search/videos' 53 const path = '/api/v1/search/videos'
48 54
55 const query = { search, sort }
56
49 return request(url) 57 return request(url)
50 .get(path) 58 .get(path)
51 .query({ search }) 59 .query(query)
52 .query({ sort })
53 .set('Accept', 'application/json') 60 .set('Accept', 'application/json')
54 .expect(200) 61 .expect(200)
55 .expect('Content-Type', /json/) 62 .expect('Content-Type', /json/)
diff --git a/shared/extra-utils/server/config.ts b/shared/extra-utils/server/config.ts
index deb77e9c0..a5f5989e0 100644
--- a/shared/extra-utils/server/config.ts
+++ b/shared/extra-utils/server/config.ts
@@ -91,6 +91,7 @@ function updateCustomSubConfig (url: string, token: string, newConfig: any) {
91 transcoding: { 91 transcoding: {
92 enabled: true, 92 enabled: true,
93 allowAdditionalExtensions: true, 93 allowAdditionalExtensions: true,
94 allowAudioFiles: true,
94 threads: 1, 95 threads: 1,
95 resolutions: { 96 resolutions: {
96 '240p': false, 97 '240p': false,
diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts
index 1505804de..0379bb109 100644
--- a/shared/extra-utils/server/follows.ts
+++ b/shared/extra-utils/server/follows.ts
@@ -1,17 +1,21 @@
1import * as request from 'supertest' 1import * as request from 'supertest'
2import { ServerInfo } from './servers' 2import { ServerInfo } from './servers'
3import { waitJobs } from './jobs' 3import { waitJobs } from './jobs'
4import { makeGetRequest, makePostBodyRequest } from '..' 4import { makePostBodyRequest } from '../requests/requests'
5 5
6function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) { 6function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
7 const path = '/api/v1/server/followers' 7 const path = '/api/v1/server/followers'
8 8
9 const query = {
10 start,
11 count,
12 sort,
13 search
14 }
15
9 return request(url) 16 return request(url)
10 .get(path) 17 .get(path)
11 .query({ start }) 18 .query(query)
12 .query({ count })
13 .query({ sort })
14 .query({ search })
15 .set('Accept', 'application/json') 19 .set('Accept', 'application/json')
16 .expect(200) 20 .expect(200)
17 .expect('Content-Type', /json/) 21 .expect('Content-Type', /json/)
@@ -42,12 +46,16 @@ function rejectFollower (url: string, token: string, follower: string, statusCod
42function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) { 46function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
43 const path = '/api/v1/server/following' 47 const path = '/api/v1/server/following'
44 48
49 const query = {
50 start,
51 count,
52 sort,
53 search
54 }
55
45 return request(url) 56 return request(url)
46 .get(path) 57 .get(path)
47 .query({ start }) 58 .query(query)
48 .query({ count })
49 .query({ sort })
50 .query({ search })
51 .set('Accept', 'application/json') 59 .set('Accept', 'application/json')
52 .expect(200) 60 .expect(200)
53 .expect('Content-Type', /json/) 61 .expect('Content-Type', /json/)
diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts
index ed41bfa48..4c7d6862a 100644
--- a/shared/extra-utils/server/servers.ts
+++ b/shared/extra-utils/server/servers.ts
@@ -246,7 +246,7 @@ async function checkTmpIsEmpty (server: ServerInfo) {
246} 246}
247 247
248async function checkDirectoryIsEmpty (server: ServerInfo, directory: string) { 248async function checkDirectoryIsEmpty (server: ServerInfo, directory: string) {
249 const testDirectory = 'test' + server.serverNumber 249 const testDirectory = 'test' + server.internalServerNumber
250 250
251 const directoryPath = join(root(), testDirectory, directory) 251 const directoryPath = join(root(), testDirectory, directory)
252 252
@@ -284,7 +284,7 @@ function cleanupTests (servers: ServerInfo[]) {
284} 284}
285 285
286async function waitUntilLog (server: ServerInfo, str: string, count = 1) { 286async function waitUntilLog (server: ServerInfo, str: string, count = 1) {
287 const logfile = join(root(), 'test' + server.serverNumber, 'logs/peertube.log') 287 const logfile = join(root(), 'test' + server.internalServerNumber, 'logs/peertube.log')
288 288
289 while (true) { 289 while (true) {
290 const buf = await readFile(logfile) 290 const buf = await readFile(logfile)
diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts
index f64a2dbad..627e17cc3 100644
--- a/shared/extra-utils/users/accounts.ts
+++ b/shared/extra-utils/users/accounts.ts
@@ -39,7 +39,7 @@ async function expectAccountFollows (url: string, nameWithDomain: string, follow
39 expect(account.followingCount).to.equal(followingCount, message) 39 expect(account.followingCount).to.equal(followingCount, message)
40} 40}
41 41
42async function checkActorFilesWereRemoved (actorUUID: string, serverNumber: number) { 42async function checkActorFilesWereRemoved (filename: string, serverNumber: number) {
43 const testDirectory = 'test' + serverNumber 43 const testDirectory = 'test' + serverNumber
44 44
45 for (const directory of [ 'avatars' ]) { 45 for (const directory of [ 'avatars' ]) {
@@ -50,7 +50,7 @@ async function checkActorFilesWereRemoved (actorUUID: string, serverNumber: numb
50 50
51 const files = await readdir(directoryPath) 51 const files = await readdir(directoryPath)
52 for (const file of files) { 52 for (const file of files) {
53 expect(file).to.not.contain(actorUUID) 53 expect(file).to.not.contain(filename)
54 } 54 }
55 } 55 }
56} 56}
diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/user-notifications.ts
index 495ff80d9..f7de542bf 100644
--- a/shared/extra-utils/users/user-notifications.ts
+++ b/shared/extra-utils/users/user-notifications.ts
@@ -380,7 +380,7 @@ async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string,
380 } 380 }
381 } 381 }
382 382
383 const commentUrl = `http://localhost:9001/videos/watch/${uuid};threadId=${threadId}` 383 const commentUrl = `http://localhost:${base.server.port}/videos/watch/${uuid};threadId=${threadId}`
384 function emailFinder (email: object) { 384 function emailFinder (email: object) {
385 return email[ 'text' ].indexOf(commentUrl) !== -1 385 return email[ 'text' ].indexOf(commentUrl) !== -1
386 } 386 }
diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts
index 2bd37b8be..0f2f0ae15 100644
--- a/shared/extra-utils/users/users.ts
+++ b/shared/extra-utils/users/users.ts
@@ -1,10 +1,11 @@
1import * as request from 'supertest' 1import * as request from 'supertest'
2import { makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests' 2import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests'
3 3
4import { UserRole } from '../../index' 4import { UserCreate, UserRole } from '../../index'
5import { NSFWPolicyType } from '../../models/videos/nsfw-policy.type' 5import { NSFWPolicyType } from '../../models/videos/nsfw-policy.type'
6import { ServerInfo, userLogin } from '..' 6import { ServerInfo, userLogin } from '..'
7import { UserAdminFlag } from '../../models/users/user-flag.model' 7import { UserAdminFlag } from '../../models/users/user-flag.model'
8import { UserRegister } from '../../models/users/user-register.model'
8 9
9type CreateUserArgs = { url: string, 10type CreateUserArgs = { url: string,
10 accessToken: string, 11 accessToken: string,
@@ -70,6 +71,27 @@ function registerUser (url: string, username: string, password: string, specialS
70 .expect(specialStatus) 71 .expect(specialStatus)
71} 72}
72 73
74function registerUserWithChannel (options: {
75 url: string,
76 user: { username: string, password: string },
77 channel: { name: string, displayName: string }
78}) {
79 const path = '/api/v1/users/register'
80 const body: UserRegister = {
81 username: options.user.username,
82 password: options.user.password,
83 email: options.user.username + '@example.com',
84 channel: options.channel
85 }
86
87 return makePostBodyRequest({
88 url: options.url,
89 path,
90 fields: body,
91 statusCodeExpected: 204
92 })
93}
94
73function getMyUserInformation (url: string, accessToken: string, specialStatus = 200) { 95function getMyUserInformation (url: string, accessToken: string, specialStatus = 200) {
74 const path = '/api/v1/users/me' 96 const path = '/api/v1/users/me'
75 97
@@ -138,12 +160,16 @@ function getUsersList (url: string, accessToken: string) {
138function getUsersListPaginationAndSort (url: string, accessToken: string, start: number, count: number, sort: string, search?: string) { 160function getUsersListPaginationAndSort (url: string, accessToken: string, start: number, count: number, sort: string, search?: string) {
139 const path = '/api/v1/users' 161 const path = '/api/v1/users'
140 162
163 const query = {
164 start,
165 count,
166 sort,
167 search
168 }
169
141 return request(url) 170 return request(url)
142 .get(path) 171 .get(path)
143 .query({ start }) 172 .query(query)
144 .query({ count })
145 .query({ sort })
146 .query({ search })
147 .set('Accept', 'application/json') 173 .set('Accept', 'application/json')
148 .set('Authorization', 'Bearer ' + accessToken) 174 .set('Authorization', 'Bearer ' + accessToken)
149 .expect(200) 175 .expect(200)
@@ -312,6 +338,7 @@ export {
312 getMyUserInformation, 338 getMyUserInformation,
313 getMyUserVideoRating, 339 getMyUserVideoRating,
314 deleteMe, 340 deleteMe,
341 registerUserWithChannel,
315 getMyUserVideoQuotaUsed, 342 getMyUserVideoQuotaUsed,
316 getUsersList, 343 getUsersList,
317 getUsersListPaginationAndSort, 344 getUsersListPaginationAndSort,
diff --git a/shared/extra-utils/videos/video-channels.ts b/shared/extra-utils/videos/video-channels.ts
index 93a257bf9..3e79cf15a 100644
--- a/shared/extra-utils/videos/video-channels.ts
+++ b/shared/extra-utils/videos/video-channels.ts
@@ -1,6 +1,6 @@
1import * as request from 'supertest' 1import * as request from 'supertest'
2import { VideoChannelCreate, VideoChannelUpdate } from '../../models/videos' 2import { VideoChannelCreate, VideoChannelUpdate } from '../../models/videos'
3import { updateAvatarRequest } from '../requests/requests' 3import { makeGetRequest, updateAvatarRequest } from '../requests/requests'
4import { getMyUserInformation, ServerInfo } from '..' 4import { getMyUserInformation, ServerInfo } from '..'
5import { User } from '../..' 5import { User } from '../..'
6 6
@@ -19,14 +19,28 @@ function getVideoChannelsList (url: string, start: number, count: number, sort?:
19 .expect('Content-Type', /json/) 19 .expect('Content-Type', /json/)
20} 20}
21 21
22function getAccountVideoChannelsList (url: string, accountName: string, specialStatus = 200) { 22function getAccountVideoChannelsList (parameters: {
23 url: string,
24 accountName: string,
25 start?: number,
26 count?: number,
27 sort?: string,
28 specialStatus?: number
29}) {
30 const { url, accountName, start, count, sort = 'createdAt', specialStatus = 200 } = parameters
31
23 const path = '/api/v1/accounts/' + accountName + '/video-channels' 32 const path = '/api/v1/accounts/' + accountName + '/video-channels'
24 33
25 return request(url) 34 return makeGetRequest({
26 .get(path) 35 url,
27 .set('Accept', 'application/json') 36 path,
28 .expect(specialStatus) 37 query: {
29 .expect('Content-Type', /json/) 38 start,
39 count,
40 sort
41 },
42 statusCodeExpected: specialStatus
43 })
30} 44}
31 45
32function addVideoChannel ( 46function addVideoChannel (
@@ -60,12 +74,13 @@ function updateVideoChannel (
60 attributes: VideoChannelUpdate, 74 attributes: VideoChannelUpdate,
61 expectedStatus = 204 75 expectedStatus = 204
62) { 76) {
63 const body = {} 77 const body: any = {}
64 const path = '/api/v1/video-channels/' + channelName 78 const path = '/api/v1/video-channels/' + channelName
65 79
66 if (attributes.displayName) body['displayName'] = attributes.displayName 80 if (attributes.displayName) body.displayName = attributes.displayName
67 if (attributes.description) body['description'] = attributes.description 81 if (attributes.description) body.description = attributes.description
68 if (attributes.support) body['support'] = attributes.support 82 if (attributes.support) body.support = attributes.support
83 if (attributes.bulkVideosSupportUpdate) body.bulkVideosSupportUpdate = attributes.bulkVideosSupportUpdate
69 84
70 return request(url) 85 return request(url)
71 .put(path) 86 .put(path)
diff --git a/shared/extra-utils/videos/video-playlists.ts b/shared/extra-utils/videos/video-playlists.ts
index 4d110a131..fd62bef19 100644
--- a/shared/extra-utils/videos/video-playlists.ts
+++ b/shared/extra-utils/videos/video-playlists.ts
@@ -252,10 +252,10 @@ function reorderVideosPlaylist (options: {
252 252
253async function checkPlaylistFilesWereRemoved ( 253async function checkPlaylistFilesWereRemoved (
254 playlistUUID: string, 254 playlistUUID: string,
255 serverNumber: number, 255 internalServerNumber: number,
256 directories = [ 'thumbnails' ] 256 directories = [ 'thumbnails' ]
257) { 257) {
258 const testDirectory = 'test' + serverNumber 258 const testDirectory = 'test' + internalServerNumber
259 259
260 for (const directory of directories) { 260 for (const directory of directories) {
261 const directoryPath = join(root(), testDirectory, directory) 261 const directoryPath = join(root(), testDirectory, directory)
diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts
index b5a07b792..debaaf9a7 100644
--- a/shared/extra-utils/videos/videos.ts
+++ b/shared/extra-utils/videos/videos.ts
@@ -355,6 +355,7 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg
355 .set('Accept', 'application/json') 355 .set('Accept', 'application/json')
356 .set('Authorization', 'Bearer ' + accessToken) 356 .set('Authorization', 'Bearer ' + accessToken)
357 .field('name', attributes.name) 357 .field('name', attributes.name)
358 .field('support', attributes.support)
358 .field('nsfw', JSON.stringify(attributes.nsfw)) 359 .field('nsfw', JSON.stringify(attributes.nsfw))
359 .field('commentsEnabled', JSON.stringify(attributes.commentsEnabled)) 360 .field('commentsEnabled', JSON.stringify(attributes.commentsEnabled))
360 .field('downloadEnabled', JSON.stringify(attributes.downloadEnabled)) 361 .field('downloadEnabled', JSON.stringify(attributes.downloadEnabled))
@@ -524,7 +525,6 @@ async function completeVideoCheck (
524 expect(video.nsfw).to.equal(attributes.nsfw) 525 expect(video.nsfw).to.equal(attributes.nsfw)
525 expect(video.description).to.equal(attributes.description) 526 expect(video.description).to.equal(attributes.description)
526 expect(video.account.id).to.be.a('number') 527 expect(video.account.id).to.be.a('number')
527 expect(video.account.uuid).to.be.a('string')
528 expect(video.account.host).to.equal(attributes.account.host) 528 expect(video.account.host).to.equal(attributes.account.host)
529 expect(video.account.name).to.equal(attributes.account.name) 529 expect(video.account.name).to.equal(attributes.account.name)
530 expect(video.channel.displayName).to.equal(attributes.channel.displayName) 530 expect(video.channel.displayName).to.equal(attributes.channel.displayName)
@@ -568,8 +568,8 @@ async function completeVideoCheck (
568 expect(file).not.to.be.undefined 568 expect(file).not.to.be.undefined
569 569
570 let extension = extname(attributes.fixture) 570 let extension = extname(attributes.fixture)
571 // Transcoding enabled on server 2, extension will always be .mp4 571 // Transcoding enabled: extension will always be .mp4
572 if (attributes.account.host === 'localhost:9002') extension = '.mp4' 572 if (attributes.files.length > 1) extension = '.mp4'
573 573
574 const magnetUri = file.magnetUri 574 const magnetUri = file.magnetUri
575 expect(file.magnetUri).to.have.lengthOf.above(2) 575 expect(file.magnetUri).to.have.lengthOf.above(2)
diff --git a/shared/models/activitypub/activitypub-actor.ts b/shared/models/activitypub/activitypub-actor.ts
index 5e30bf783..53ec579bc 100644
--- a/shared/models/activitypub/activitypub-actor.ts
+++ b/shared/models/activitypub/activitypub-actor.ts
@@ -21,7 +21,6 @@ export interface ActivityPubActor {
21 attributedTo: ActivityPubAttributedTo[] 21 attributedTo: ActivityPubAttributedTo[]
22 22
23 support?: string 23 support?: string
24 uuid: string
25 publicKey: { 24 publicKey: {
26 id: string 25 id: string
27 owner: string 26 owner: string
diff --git a/shared/models/actors/account.model.ts b/shared/models/actors/account.model.ts
index 043a2507e..2ff4b9f5e 100644
--- a/shared/models/actors/account.model.ts
+++ b/shared/models/actors/account.model.ts
@@ -10,7 +10,6 @@ export interface Account extends Actor {
10 10
11export interface AccountSummary { 11export interface AccountSummary {
12 id: number 12 id: number
13 uuid: string
14 name: string 13 name: string
15 displayName: string 14 displayName: string
16 url: string 15 url: string
diff --git a/shared/models/actors/actor.model.ts b/shared/models/actors/actor.model.ts
index a3953874d..1dbf5f638 100644
--- a/shared/models/actors/actor.model.ts
+++ b/shared/models/actors/actor.model.ts
@@ -2,7 +2,6 @@ import { Avatar } from '../avatars/avatar.model'
2 2
3export interface Actor { 3export interface Actor {
4 id: number 4 id: number
5 uuid: string
6 url: string 5 url: string
7 name: string 6 name: string
8 host: string 7 host: string
diff --git a/shared/models/server/custom-config.model.ts b/shared/models/server/custom-config.model.ts
index ca52eff4b..4cc379b2a 100644
--- a/shared/models/server/custom-config.model.ts
+++ b/shared/models/server/custom-config.model.ts
@@ -54,6 +54,7 @@ export interface CustomConfig {
54 transcoding: { 54 transcoding: {
55 enabled: boolean 55 enabled: boolean
56 allowAdditionalExtensions: boolean 56 allowAdditionalExtensions: boolean
57 allowAudioFiles: boolean
57 threads: number 58 threads: number
58 resolutions: { 59 resolutions: {
59 '240p': boolean 60 '240p': boolean
diff --git a/shared/models/users/user-register.model.ts b/shared/models/users/user-register.model.ts
new file mode 100644
index 000000000..ce5c9c3d2
--- /dev/null
+++ b/shared/models/users/user-register.model.ts
@@ -0,0 +1,10 @@
1export interface UserRegister {
2 username: string
3 password: string
4 email: string
5
6 channel?: {
7 name: string
8 displayName: string
9 }
10}
diff --git a/shared/models/videos/channel/video-channel-update.model.ts b/shared/models/videos/channel/video-channel-update.model.ts
index 3626ce8a9..8dde9188b 100644
--- a/shared/models/videos/channel/video-channel-update.model.ts
+++ b/shared/models/videos/channel/video-channel-update.model.ts
@@ -1,5 +1,7 @@
1export interface VideoChannelUpdate { 1export interface VideoChannelUpdate {
2 displayName: string 2 displayName?: string
3 description?: string 3 description?: string
4 support?: string 4 support?: string
5
6 bulkVideosSupportUpdate?: boolean
5} 7}
diff --git a/shared/models/videos/channel/video-channel.model.ts b/shared/models/videos/channel/video-channel.model.ts
index 14a813f8f..de4c26b3d 100644
--- a/shared/models/videos/channel/video-channel.model.ts
+++ b/shared/models/videos/channel/video-channel.model.ts
@@ -12,7 +12,6 @@ export interface VideoChannel extends Actor {
12 12
13export interface VideoChannelSummary { 13export interface VideoChannelSummary {
14 id: number 14 id: number
15 uuid: string
16 name: string 15 name: string
17 displayName: string 16 displayName: string
18 url: string 17 url: string
diff --git a/shared/models/videos/playlist/video-playlist-update.model.ts b/shared/models/videos/playlist/video-playlist-update.model.ts
index 0ff5bcb0f..a6a3f74d9 100644
--- a/shared/models/videos/playlist/video-playlist-update.model.ts
+++ b/shared/models/videos/playlist/video-playlist-update.model.ts
@@ -1,8 +1,8 @@
1import { VideoPlaylistPrivacy } from './video-playlist-privacy.model' 1import { VideoPlaylistPrivacy } from './video-playlist-privacy.model'
2 2
3export interface VideoPlaylistUpdate { 3export interface VideoPlaylistUpdate {
4 displayName: string 4 displayName?: string
5 privacy: VideoPlaylistPrivacy 5 privacy?: VideoPlaylistPrivacy
6 6
7 description?: string 7 description?: string
8 videoChannelId?: number 8 videoChannelId?: number
diff --git a/shared/models/videos/video-resolution.enum.ts b/shared/models/videos/video-resolution.enum.ts
index 7da5e7100..51efa2e8b 100644
--- a/shared/models/videos/video-resolution.enum.ts
+++ b/shared/models/videos/video-resolution.enum.ts
@@ -5,7 +5,8 @@ export enum VideoResolution {
5 H_360P = 360, 5 H_360P = 360,
6 H_480P = 480, 6 H_480P = 480,
7 H_720P = 720, 7 H_720P = 720,
8 H_1080P = 1080 8 H_1080P = 1080,
9 H_4K = 2160
9} 10}
10 11
11/** 12/**
@@ -33,11 +34,14 @@ function getBaseBitrate (resolution: VideoResolution) {
33 // quality according to Google Live Encoder: 1,500 - 4,000 Kbps 34 // quality according to Google Live Encoder: 1,500 - 4,000 Kbps
34 // Quality according to YouTube Video Info: 1752 Kbps 35 // Quality according to YouTube Video Info: 1752 Kbps
35 return 1750 * 1000 36 return 1750 * 1000
36 case VideoResolution.H_1080P: // fallthrough 37 case VideoResolution.H_1080P:
37 default:
38 // quality according to Google Live Encoder: 3000 - 6000 Kbps 38 // quality according to Google Live Encoder: 3000 - 6000 Kbps
39 // Quality according to YouTube Video Info: 3277 Kbps 39 // Quality according to YouTube Video Info: 3277 Kbps
40 return 3300 * 1000 40 return 3300 * 1000
41 case VideoResolution.H_4K: // fallthrough
42 default:
43 // quality according to Google Live Encoder: 13000 - 34000 Kbps
44 return 15000 * 1000
41 } 45 }
42} 46}
43 47
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml
index de610893c..5a4f6fcb2 100644
--- a/support/doc/api/openapi.yaml
+++ b/support/doc/api/openapi.yaml
@@ -38,7 +38,7 @@ info:
38 } 38 }
39 ``` 39 ```
40externalDocs: 40externalDocs:
41 url: https://docs.joinpeertube.org/api.html 41 url: https://docs.joinpeertube.org/#/api-rest-reference.html
42tags: 42tags:
43 - name: Accounts 43 - name: Accounts
44 description: > 44 description: >
@@ -99,6 +99,7 @@ x-tagGroups:
99 - name: Videos 99 - name: Videos
100 tags: 100 tags:
101 - Video 101 - Video
102 - Video Caption
102 - Video Channel 103 - Video Channel
103 - Video Comment 104 - Video Comment
104 - Video Following 105 - Video Following
@@ -152,7 +153,7 @@ paths:
152 content: 153 content:
153 application/json: 154 application/json:
154 schema: 155 schema:
155 $ref: '#/components/schemas/Video' 156 $ref: '#/components/schemas/VideoListResponse'
156 x-code-samples: 157 x-code-samples:
157 - lang: JavaScript 158 - lang: JavaScript
158 source: | 159 source: |
@@ -575,9 +576,7 @@ paths:
575 content: 576 content:
576 application/json: 577 application/json:
577 schema: 578 schema:
578 type: array 579 $ref: '#/components/schemas/VideoListResponse'
579 items:
580 $ref: '#/components/schemas/Video'
581 /users/me/subscriptions: 580 /users/me/subscriptions:
582 get: 581 get:
583 summary: Get subscriptions of the current user 582 summary: Get subscriptions of the current user
@@ -638,9 +637,7 @@ paths:
638 content: 637 content:
639 application/json: 638 application/json:
640 schema: 639 schema:
641 type: array 640 $ref: '#/components/schemas/VideoListResponse'
642 items:
643 $ref: '#/components/schemas/Video'
644 '/users/me/subscriptions/{uri}': 641 '/users/me/subscriptions/{uri}':
645 get: 642 get:
646 summary: Get subscription of the current user for a given uri 643 summary: Get subscription of the current user for a given uri
@@ -730,9 +727,7 @@ paths:
730 content: 727 content:
731 application/json: 728 application/json:
732 schema: 729 schema:
733 type: array 730 $ref: '#/components/schemas/VideoListResponse'
734 items:
735 $ref: '#/components/schemas/Video'
736 /videos/categories: 731 /videos/categories:
737 get: 732 get:
738 summary: Get list of video licences known by the server 733 summary: Get list of video licences known by the server
@@ -1025,7 +1020,7 @@ paths:
1025 description: Video preview file 1020 description: Video preview file
1026 type: string 1021 type: string
1027 privacy: 1022 privacy:
1028 $ref: '#/components/schemas/VideoPrivacy' 1023 $ref: '#/components/schemas/VideoPrivacySet'
1029 category: 1024 category:
1030 description: Video category 1025 description: Video category
1031 type: string 1026 type: string
@@ -1129,7 +1124,7 @@ paths:
1129 description: Video preview file 1124 description: Video preview file
1130 type: string 1125 type: string
1131 privacy: 1126 privacy:
1132 $ref: '#/components/schemas/VideoPrivacy' 1127 $ref: '#/components/schemas/VideoPrivacySet'
1133 category: 1128 category:
1134 description: Video category 1129 description: Video category
1135 type: string 1130 type: string
@@ -1247,6 +1242,58 @@ paths:
1247 type: array 1242 type: array
1248 items: 1243 items:
1249 $ref: '#/components/schemas/VideoBlacklist' 1244 $ref: '#/components/schemas/VideoBlacklist'
1245 /videos/{id}/captions:
1246 get:
1247 summary: Get list of video's captions
1248 tags:
1249 - Video Caption
1250 parameters:
1251 - $ref: '#/components/parameters/id2'
1252 responses:
1253 '200':
1254 description: successful operation
1255 content:
1256 application/json:
1257 schema:
1258 type: object
1259 properties:
1260 total:
1261 type: integer
1262 data:
1263 type: array
1264 items:
1265 $ref: '#/components/schemas/VideoCaption'
1266 /videos/{id}/captions/{captionLanguage}:
1267 put:
1268 summary: Add or replace a video caption
1269 tags:
1270 - Video Caption
1271 parameters:
1272 - $ref: '#/components/parameters/id2'
1273 - $ref: '#/components/parameters/captionLanguage'
1274 requestBody:
1275 content:
1276 multipart/form-data:
1277 schema:
1278 type: object
1279 properties:
1280 captionfile:
1281 description: The file to upload.
1282 type: string
1283 format: binary
1284 responses:
1285 '204':
1286 $ref: '#/paths/~1users~1me/put/responses/204'
1287 delete:
1288 summary: Delete a video caption
1289 tags:
1290 - Video Caption
1291 parameters:
1292 - $ref: '#/components/parameters/id2'
1293 - $ref: '#/components/parameters/captionLanguage'
1294 responses:
1295 '204':
1296 $ref: '#/paths/~1users~1me/put/responses/204'
1250 /video-channels: 1297 /video-channels:
1251 get: 1298 get:
1252 summary: Get list of video channels 1299 summary: Get list of video channels
@@ -1275,7 +1322,10 @@ paths:
1275 '204': 1322 '204':
1276 $ref: '#/paths/~1users~1me/put/responses/204' 1323 $ref: '#/paths/~1users~1me/put/responses/204'
1277 requestBody: 1324 requestBody:
1278 $ref: '#/components/requestBodies/VideoChannelInput' 1325 content:
1326 application/json:
1327 schema:
1328 $ref: '#/components/schemas/VideoChannelCreate'
1279 '/video-channels/{channelHandle}': 1329 '/video-channels/{channelHandle}':
1280 get: 1330 get:
1281 summary: Get a video channel by its id 1331 summary: Get a video channel by its id
@@ -1302,7 +1352,10 @@ paths:
1302 '204': 1352 '204':
1303 $ref: '#/paths/~1users~1me/put/responses/204' 1353 $ref: '#/paths/~1users~1me/put/responses/204'
1304 requestBody: 1354 requestBody:
1305 $ref: '#/components/requestBodies/VideoChannelInput' 1355 content:
1356 application/json:
1357 schema:
1358 $ref: '#/components/schemas/VideoChannelUpdate'
1306 delete: 1359 delete:
1307 summary: Delete a video channel by its id 1360 summary: Delete a video channel by its id
1308 security: 1361 security:
@@ -1318,6 +1371,7 @@ paths:
1318 get: 1371 get:
1319 summary: Get videos of a video channel by its id 1372 summary: Get videos of a video channel by its id
1320 tags: 1373 tags:
1374 - Video
1321 - Video Channel 1375 - Video Channel
1322 parameters: 1376 parameters:
1323 - $ref: '#/components/parameters/channelHandle' 1377 - $ref: '#/components/parameters/channelHandle'
@@ -1327,7 +1381,7 @@ paths:
1327 content: 1381 content:
1328 application/json: 1382 application/json:
1329 schema: 1383 schema:
1330 $ref: '#/components/schemas/Video' 1384 $ref: '#/components/schemas/VideoListResponse'
1331 '/accounts/{name}/video-channels': 1385 '/accounts/{name}/video-channels':
1332 get: 1386 get:
1333 summary: Get video channels of an account by its name 1387 summary: Get video channels of an account by its name
@@ -1443,7 +1497,7 @@ paths:
1443 schema: 1497 schema:
1444 $ref: '#/components/schemas/CommentThreadPostResponse' 1498 $ref: '#/components/schemas/CommentThreadPostResponse'
1445 delete: 1499 delete:
1446 summary: 'Delete a comment in a comment therad by its id, of a video by its id' 1500 summary: 'Delete a comment in a comment thread by its id, of a video by its id'
1447 security: 1501 security:
1448 - OAuth2: [] 1502 - OAuth2: []
1449 tags: 1503 tags:
@@ -1487,9 +1541,7 @@ paths:
1487 content: 1541 content:
1488 application/json: 1542 application/json:
1489 schema: 1543 schema:
1490 type: array 1544 $ref: '#/components/schemas/VideoListResponse'
1491 items:
1492 $ref: '#/components/schemas/Video'
1493servers: 1545servers:
1494 - url: 'https://peertube.cpy.re/api/v1' 1546 - url: 'https://peertube.cpy.re/api/v1'
1495 description: Live Test Server (live data - stable version) 1547 description: Live Test Server (live data - stable version)
@@ -1611,6 +1663,13 @@ components:
1611 description: The video id or uuid 1663 description: The video id or uuid
1612 schema: 1664 schema:
1613 type: string 1665 type: string
1666 captionLanguage:
1667 name: captionLanguage
1668 in: path
1669 required: true
1670 description: The caption language
1671 schema:
1672 type: string
1614 channelHandle: 1673 channelHandle:
1615 name: channelHandle 1674 name: channelHandle
1616 in: path 1675 in: path
@@ -1722,12 +1781,6 @@ components:
1722 type: array 1781 type: array
1723 items: 1782 items:
1724 type: string 1783 type: string
1725 requestBodies:
1726 VideoChannelInput:
1727 content:
1728 application/json:
1729 schema:
1730 $ref: '#/components/schemas/VideoChannelInput'
1731 securitySchemes: 1784 securitySchemes:
1732 OAuth2: 1785 OAuth2:
1733 description: > 1786 description: >
@@ -1739,7 +1792,7 @@ components:
1739 1792
1740 - Have an account with sufficient authorization levels 1793 - Have an account with sufficient authorization levels
1741 1794
1742 - [Generate](https://docs.joinpeertube.org/lang/en/devdocs/rest.html) a 1795 - [Generate](https://docs.joinpeertube.org/#/api-rest-getting-started) a
1743 Bearer Token 1796 Bearer Token
1744 1797
1745 - Make Authenticated Requests 1798 - Make Authenticated Requests
@@ -1764,12 +1817,23 @@ components:
1764 type: string 1817 type: string
1765 label: 1818 label:
1766 type: string 1819 type: string
1767 VideoPrivacy: 1820 VideoPrivacySet:
1768 type: string 1821 type: integer
1769 enum: 1822 enum:
1770 - Public 1823 - 1
1771 - Unlisted 1824 - 2
1772 - Private 1825 - 3
1826 description: 'The video privacy (Public = 1, Unlisted = 2, Private = 3)'
1827 VideoPrivacyConstant:
1828 properties:
1829 id:
1830 type: integer
1831 enum:
1832 - 1
1833 - 2
1834 - 3
1835 label:
1836 type: string
1773 Video: 1837 Video:
1774 properties: 1838 properties:
1775 id: 1839 id:
@@ -1789,7 +1853,7 @@ components:
1789 language: 1853 language:
1790 $ref: '#/components/schemas/VideoConstantString' 1854 $ref: '#/components/schemas/VideoConstantString'
1791 privacy: 1855 privacy:
1792 $ref: '#/components/schemas/VideoPrivacy' 1856 $ref: '#/components/schemas/VideoPrivacyConstant'
1793 description: 1857 description:
1794 type: string 1858 type: string
1795 duration: 1859 duration:
@@ -1917,6 +1981,12 @@ components:
1917 type: array 1981 type: array
1918 items: 1982 items:
1919 $ref: '#/components/schemas/VideoCommentThreadTree' 1983 $ref: '#/components/schemas/VideoCommentThreadTree'
1984 VideoCaption:
1985 properties:
1986 language:
1987 $ref: '#/components/schemas/VideoConstantString'
1988 captionPath:
1989 type: string
1920 Avatar: 1990 Avatar:
1921 properties: 1991 properties:
1922 path: 1992 path:
@@ -1966,6 +2036,13 @@ components:
1966 autoPlayVideo: 2036 autoPlayVideo:
1967 type: boolean 2037 type: boolean
1968 role: 2038 role:
2039 type: integer
2040 enum:
2041 - 0
2042 - 1
2043 - 2
2044 description: 'The user role (Admin = 0, Moderator = 1, User = 2)'
2045 roleLabel:
1969 type: string 2046 type: string
1970 enum: 2047 enum:
1971 - User 2048 - User
@@ -2096,6 +2173,14 @@ components:
2096 properties: 2173 properties:
2097 comment: 2174 comment:
2098 $ref: '#/components/schemas/VideoComment' 2175 $ref: '#/components/schemas/VideoComment'
2176 VideoListResponse:
2177 properties:
2178 total:
2179 type: number
2180 data:
2181 type: array
2182 items:
2183 $ref: '#/components/schemas/Video'
2099 AddUser: 2184 AddUser:
2100 properties: 2185 properties:
2101 username: 2186 username:
@@ -2115,12 +2200,11 @@ components:
2115 description: 'The user daily video quota ' 2200 description: 'The user daily video quota '
2116 role: 2201 role:
2117 type: integer 2202 type: integer
2118 format: int32
2119 enum: 2203 enum:
2120 - 0 2204 - 0
2121 - 1 2205 - 1
2122 - 2 2206 - 2
2123 description: 'The user role ' 2207 description: 'The user role (Admin = 0, Moderator = 1, User = 2)'
2124 required: 2208 required:
2125 - username 2209 - username
2126 - password 2210 - password
@@ -2143,8 +2227,12 @@ components:
2143 type: string 2227 type: string
2144 description: 'The updated daily video quota of the user ' 2228 description: 'The updated daily video quota of the user '
2145 role: 2229 role:
2146 type: string 2230 type: integer
2147 description: 'The updated role of the user ' 2231 enum:
2232 - 0
2233 - 1
2234 - 2
2235 description: 'The user role (Admin = 0, Moderator = 1, User = 2)'
2148 required: 2236 required:
2149 - id 2237 - id
2150 - email 2238 - email
@@ -2206,10 +2294,28 @@ components:
2206 - username 2294 - username
2207 - password 2295 - password
2208 - email 2296 - email
2209 VideoChannelInput: 2297 VideoChannelCreate:
2210 properties: 2298 properties:
2211 name: 2299 name:
2212 type: string 2300 type: string
2301 displayName:
2302 type: string
2303 description:
2304 type: string
2305 support:
2306 type: string
2307 required:
2308 - name
2309 - displayName
2310 VideoChannelUpdate:
2311 properties:
2312 displayName:
2313 type: string
2213 description: 2314 description:
2214 type: string 2315 type: string
2316 support:
2317 type: string
2318 bulkVideosSupportUpdate:
2319 type: boolean
2320 description: 'Update all videos support field of this channel'
2215 2321
diff --git a/support/doc/api/quickstart.md b/support/doc/api/quickstart.md
index 00874a1c9..2222be741 100644
--- a/support/doc/api/quickstart.md
+++ b/support/doc/api/quickstart.md
@@ -47,7 +47,7 @@ $ curl -H 'Authorization: Bearer 90286a0bdf0f7315d9d3fe8dabf9e1d2be9c97d0' https
47``` 47```
48 48
49 49
50### List videos 50## List videos
51 51
52```bash 52```bash
53$ curl https://peertube.example.com/api/v1/videos 53$ curl https://peertube.example.com/api/v1/videos
diff --git a/support/doc/development/client/code.md b/support/doc/development/client/code.md
deleted file mode 100644
index 235116e78..000000000
--- a/support/doc/development/client/code.md
+++ /dev/null
@@ -1,67 +0,0 @@
1# Client code documentation
2
3The client is a HTML/CSS/JavaScript web application (single page application -> SPA) developed with [TypeScript](https://www.typescriptlang.org/)/[Angular](https://angular.io/).
4
5
6## Technologies
7
8 * [TypeScript](https://www.typescriptlang.org/) -> Language
9 * [Angular](https://angular.io) -> JavaScript framework
10 * [SASS](http://sass-lang.com/) -> CSS framework
11 * [Webpack](https://webpack.js.org/) -> Source builder (compile TypeScript, SASS files, bundle them...)
12 * [Bootstrap](http://getbootstrap.com/) -> CSS framework
13 * [WebTorrent](https://webtorrent.io/) -> JavaScript library to make P2P in the browser
14 * [VideoJS](http://videojs.com/) -> JavaScript player framework
15
16
17## Files
18
19The client files are in the `client` directory. The Webpack 2 configurations files are in `client/config` and the source files in `client/src`.
20The client modules description are in the [client/package.json](/client/package.json). There are many modules that are used to compile the web application in development or production mode.
21Here is the description of the useful `client` files directory:
22
23 tslint.json -> TypeScript linter rules
24 tsconfig.json -> TypeScript configuration for the compilation
25 .bootstraprc -> Bootstrap configuration file (which module we need)
26 config -> Webpack configuration files
27 src
28 |__ app -> TypeScript files for Angular application
29 |__ assets -> static files (images...)
30 |__ sass -> SASS files that are global for the application
31 |__ standalone -> files outside the Angular application (embed HTML page...)
32 |__ index.html -> root HTML file for our Angular application
33 |__ main.ts -> Main TypeScript file that boostraps our Angular application
34 |__ polyfills.ts -> Polyfills imports (ES 2015...)
35
36Details of the Angular application file structure. It tries to follow [the official Angular styleguide](https://angular.io/docs/ts/latest/guide/style-guide.html).
37
38 app
39 |__ +admin -> Admin components (followers, users...)
40 |__ account -> Account components (password change...)
41 |__ core -> Core components/services
42 |__ header -> Header components (logo, search...)
43 |__ login -> Login component
44 |__ menu -> Menu component (on the left)
45 |__ shared -> Shared components/services (search component, REST services...)
46 |__ signup -> Signup form
47 |__ videos -> Video components (list, watch, upload...)
48 |__ app.component.{html,scss,ts} -> Main application component
49 |__ app-routing.module.ts -> Main Angular routes
50 |__ app.module.ts -> Angular root module that imports all submodules we need
51
52## Conventions
53
54Uses [TSLint](https://palantir.github.io/tslint/) for TypeScript linting and [Angular styleguide](https://angular.io/docs/ts/latest/guide/style-guide.html).
55
56## Concepts
57
58In a Angular application, we create components that we put together. Each component is defined by an HTML structure, a TypeScript file and optionally a SASS file.
59If you are not familiar with Angular I recommend you to read the [quickstart guide](https://angular.io/docs/ts/latest/quickstart.html).
60
61## Components tree
62
63![Components tree](/support/doc/development/client/components-tree.svg)
64
65## Newcomers
66
67The main client component is `app.component.ts`. You can begin to look at this file. Then you could navigate in the different submodules to see how components are built.
diff --git a/support/doc/development/client/components-tree.png b/support/doc/development/client/components-tree.png
deleted file mode 100644
index 09582d742..000000000
--- a/support/doc/development/client/components-tree.png
+++ /dev/null
Binary files differ
diff --git a/support/doc/development/client/components-tree.svg b/support/doc/development/client/components-tree.svg
deleted file mode 100644
index fd6951d93..000000000
--- a/support/doc/development/client/components-tree.svg
+++ /dev/null
@@ -1,2 +0,0 @@
1<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
2<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" width="1141px" height="311px" version="1.1" content="&lt;mxfile userAgent=&quot;Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0&quot; version=&quot;8.9.9&quot; editor=&quot;www.draw.io&quot; type=&quot;device&quot;&gt;&lt;diagram name=&quot;Page-1&quot; id=&quot;8be7db5e-9885-9541-e5e4-cf9e4eb3a109&quot;&gt;7Zpbb5swFMc/TaTtZQLMLY9d1nYP2zSp2u3RwQ54dTAypkn36WeDSSCmVdcR3FTpQwXHN/z7G59zHGZgsd5ec1hknxnCdOY5aDsDH2aeFzuB/K8M943Bd93GkHKCGlPHcEP+YG10tLUiCJe9ioIxKkjRNyYsz3EiejbIOdv0q60Y7Y9awBQbhpsEUtP6gyCRaasbzvcFHzFJMz107EVNwRImtylnVa7Hm3lgVf81xWvY9qUnWmYQsU3HBC5nYMEZE83VervAVKFtsTXtrh4o3T03x7l4SgNPT6gU9+3cMZIo9C3jImMpyyG93Fvf1/PDqgdH3mViTeWlKy/xloifyvwu0He/2pJc8PtOkbr9pTsoBeTiQqkmDTnLcWu7IpTqOjhHbY2EwrIkSWPUVdQQv7EQ93opwUowado//ifGCl1vxXKhq7nq3kSmKZas4omG4ulFCHmKdS1NTuHqNNOYrzFbYzlHWYFjCgW5668sqBdouqu3F0leaJ2GNQPOWbNnahZb08w9a/ZMzSJrmnlnzZ6pGbCmWTymZk/F9rC2gxyeRTSaiKAfvFKCPpiKYGiF4CO7yBR0/f+kq5t+ZUQO7Dk6k5jPdbCjEwm3DX7aLppn0K0ONNo9xtNkG3XreEyOl/RSTLWt6LHvIK10pxdFUWdw60K6Na1eDz6lMt1TkDcZEfimgPU8NjLh7KM+dFor6fcWjDJe9wOwiwIc1X6Ts1vcKZmHEYDhY27uDnOBt4+6MF0K/P5CbRO8TSd9bG1ZN3N0RmA76obz8Ko7hWAEmGs8tBWMtKHrOYD8Z80Ca5qN6wVe27vk29IFGP7jO0GYlTMvhGvlEPJlWewmdgQ3giCOV8mQGwmTGC9XI7mR+CDeaaOSKfyIbzC+REQFY2+qgjKIZPuqQFDgt5I6lQO/R+ROXqainnxjWvJDi2zWq3csgQIcI39IoNhbgnAkPx8c+vkofBcYEsUDCgUjKBQYCn0i5fFCp2mQ+laRhgbSH1Ak2YkzNcLRSZlGBtOLJJE+8tRXauBa3J1j891nKclPHOnu1wwbSHdBzznYa3/O6gZ77Wq3EIV70whz6pnTkGiuLdHARMcQr1A0YC3fnZuuGq2P6VUmSaNsZlHtrtlBesUoVd+knDZU9zCkBAbU+VBAGY3A1DWY1um/6nZZlfjk0Xr22AIzqfxWYn7qSA8DyyGkg/nPGEgHEqAlq15A+mPwG6D8INLQt3k4ZZ4ADpxCfVUf9nnOF6aOra7q7/Be6CnUfykRRTaVMM8JB5T4rB53l/a/Qg3mjk0NzB2mdYiLDOY5pkfcvyfB6zoTngzI2/03t823A/vvmsHlXw==&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g transform="translate(0.5,0.5)"><path d="M 390 80 L 390 104 L 130 104 L 130 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 130 126.88 L 126.5 119.88 L 130 121.63 L 133.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 280 104 L 280 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 280 126.88 L 276.5 119.88 L 280 121.63 L 283.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 560 104 L 560 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 560 126.88 L 556.5 119.88 L 560 121.63 L 563.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 430 104 L 430 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 430 126.88 L 426.5 119.88 L 430 121.63 L 433.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 690 104 L 690 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 690 126.88 L 686.5 119.88 L 690 121.63 L 693.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 820 104 L 820 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 820 126.88 L 816.5 119.88 L 820 121.63 L 823.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 950 104 L 950 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 950 126.88 L 946.5 119.88 L 950 121.63 L 953.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 390 80 L 390 104 L 1080 104 L 1080 121.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 1080 126.88 L 1076.5 119.88 L 1080 121.63 L 1083.5 119.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><ellipse cx="390" cy="40" rx="60" ry="40" fill="#e1d5e7" stroke="#9673a6" pointer-events="none"/><g transform="translate(345.5,34.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="88" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 89px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">App component</div></div></foreignObject><text x="44" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">App component</text></switch></g><path d="M 430 208 L 430 232 L 370 232 L 370 250.13" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 370 255.38 L 366.5 248.38 L 370 250.13 L 373.5 248.38 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 430 208 L 430 232 L 470 232 L 470 250.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 470 255.88 L 466.5 248.88 L 470 250.63 L 473.5 248.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 430 208 L 430 232 L 570 232 L 570 250.13" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 570 255.38 L 566.5 248.38 L 570 250.13 L 573.5 248.38 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><ellipse cx="430" cy="168" rx="60" ry="40" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(408.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="43" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 44px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Videos </div></div></foreignObject><text x="22" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Videos </text></switch></g><ellipse cx="570" cy="282" rx="40" ry="25" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(524.5,262.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="91" height="38" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 91px; white-space: normal; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Edit (upload/update)<div><br /></div></div></div></foreignObject><text x="46" y="25" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Edit (upload/update)&lt;div&gt;&lt;br&gt;&lt;/div&gt;</text></switch></g><ellipse cx="470" cy="282" rx="40" ry="25" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(459.5,275.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="21" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 22px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">List</div></div></foreignObject><text x="11" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">List</text></switch></g><ellipse cx="370" cy="282" rx="40" ry="25" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(352.5,275.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="34" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 35px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Watch</div></div></foreignObject><text x="17" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Watch</text></switch></g><ellipse cx="560" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(537.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="45" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Account</div></div></foreignObject><text x="23" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Account</text></switch></g><ellipse cx="280" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(263.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="32" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 33px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Login</div></div></foreignObject><text x="16" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Login</text></switch></g><path d="M 130 208 L 130 231 L 45 231 L 45 246.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 45 251.88 L 41.5 244.88 L 45 246.63 L 48.5 244.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 130 208 L 130 231 L 155 231 L 155 246.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 155 251.88 L 151.5 244.88 L 155 246.63 L 158.5 244.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 130 208 L 130 231 L 260 231 L 260 246.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 260 251.88 L 256.5 244.88 L 260 246.63 L 263.5 244.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><ellipse cx="130" cy="168" rx="60" ry="40" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(111.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="36" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 37px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Admin</div></div></foreignObject><text x="18" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Admin</text></switch></g><ellipse cx="45" cy="282" rx="45" ry="28.5" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(22.5,275.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="44" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 45px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Follows</div></div></foreignObject><text x="22" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Follows</text></switch></g><ellipse cx="155" cy="282" rx="45" ry="28.5" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(116.5,275.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="77" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 78px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video abuses</div></div></foreignObject><text x="39" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Video abuses</text></switch></g><ellipse cx="260" cy="282" rx="40" ry="28.5" fill="#dae8fc" stroke="#6c8ebf" pointer-events="none"/><g transform="translate(243.5,275.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="33" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 34px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Users</div></div></foreignObject><text x="17" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Users</text></switch></g><ellipse cx="690" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(673.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="33" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 34px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">About</div></div></foreignObject><text x="17" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">About</text></switch></g><ellipse cx="820" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(773.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="92" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 93px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>Page Not Found</div></div></div></foreignObject><text x="46" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">&lt;div&gt;Page Not Found&lt;/div&gt;</text></switch></g><ellipse cx="950" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(916.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="66" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 67px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><div>My Account</div></div></div></foreignObject><text x="33" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">&lt;div&gt;My Account&lt;/div&gt;</text></switch></g><ellipse cx="1080" cy="168" rx="60" ry="40" fill="#d5e8d4" stroke="#82b366" pointer-events="none"/><g transform="translate(1034.5,162.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="90" height="11" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 11px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 91px; white-space: nowrap; overflow-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Video Channels</div></div></foreignObject><text x="45" y="11" fill="#000000" text-anchor="middle" font-size="11px" font-family="Helvetica">Video Channels</text></switch></g></g></svg> \ No newline at end of file
diff --git a/support/doc/development/client/components-tree.xml b/support/doc/development/client/components-tree.xml
deleted file mode 100644
index 5a37c48bc..000000000
--- a/support/doc/development/client/components-tree.xml
+++ /dev/null
@@ -1 +0,0 @@
1<mxfile userAgent="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0" version="8.9.9" editor="www.draw.io" type="device"><diagram name="Page-1" id="8be7db5e-9885-9541-e5e4-cf9e4eb3a109">7Zpbb5swFMc/TaTtZQLMLY9d1nYP2zSp2u3RwQ54dTAypkn36WeDSSCmVdcR3FTpQwXHN/z7G59zHGZgsd5ec1hknxnCdOY5aDsDH2aeFzuB/K8M943Bd93GkHKCGlPHcEP+YG10tLUiCJe9ioIxKkjRNyYsz3EiejbIOdv0q60Y7Y9awBQbhpsEUtP6gyCRaasbzvcFHzFJMz107EVNwRImtylnVa7Hm3lgVf81xWvY9qUnWmYQsU3HBC5nYMEZE83VervAVKFtsTXtrh4o3T03x7l4SgNPT6gU9+3cMZIo9C3jImMpyyG93Fvf1/PDqgdH3mViTeWlKy/xloifyvwu0He/2pJc8PtOkbr9pTsoBeTiQqkmDTnLcWu7IpTqOjhHbY2EwrIkSWPUVdQQv7EQ93opwUowado//ifGCl1vxXKhq7nq3kSmKZas4omG4ulFCHmKdS1NTuHqNNOYrzFbYzlHWYFjCgW5668sqBdouqu3F0leaJ2GNQPOWbNnahZb08w9a/ZMzSJrmnlnzZ6pGbCmWTymZk/F9rC2gxyeRTSaiKAfvFKCPpiKYGiF4CO7yBR0/f+kq5t+ZUQO7Dk6k5jPdbCjEwm3DX7aLppn0K0ONNo9xtNkG3XreEyOl/RSTLWt6LHvIK10pxdFUWdw60K6Na1eDz6lMt1TkDcZEfimgPU8NjLh7KM+dFor6fcWjDJe9wOwiwIc1X6Ts1vcKZmHEYDhY27uDnOBt4+6MF0K/P5CbRO8TSd9bG1ZN3N0RmA76obz8Ko7hWAEmGs8tBWMtKHrOYD8Z80Ca5qN6wVe27vk29IFGP7jO0GYlTMvhGvlEPJlWewmdgQ3giCOV8mQGwmTGC9XI7mR+CDeaaOSKfyIbzC+REQFY2+qgjKIZPuqQFDgt5I6lQO/R+ROXqainnxjWvJDi2zWq3csgQIcI39IoNhbgnAkPx8c+vkofBcYEsUDCgUjKBQYCn0i5fFCp2mQ+laRhgbSH1Ak2YkzNcLRSZlGBtOLJJE+8tRXauBa3J1j891nKclPHOnu1wwbSHdBzznYa3/O6gZ77Wq3EIV70whz6pnTkGiuLdHARMcQr1A0YC3fnZuuGq2P6VUmSaNsZlHtrtlBesUoVd+knDZU9zCkBAbU+VBAGY3A1DWY1um/6nZZlfjk0Xr22AIzqfxWYn7qSA8DyyGkg/nPGEgHEqAlq15A+mPwG6D8INLQt3k4ZZ4ADpxCfVUf9nnOF6aOra7q7/Be6CnUfykRRTaVMM8JB5T4rB53l/a/Qg3mjk0NzB2mdYiLDOY5pkfcvyfB6zoTngzI2/03t823A/vvmsHlXw==</diagram></mxfile> \ No newline at end of file
diff --git a/support/doc/development/server/code.md b/support/doc/development/server/code.md
deleted file mode 100644
index 3894c2542..000000000
--- a/support/doc/development/server/code.md
+++ /dev/null
@@ -1,58 +0,0 @@
1# Server code documentation
2
3The server is a web server developed with [TypeScript](https://www.typescriptlang.org/)/[Express](http://expressjs.com).
4
5
6## Technologies
7
8 * [TypeScript](https://www.typescriptlang.org/) -> Language
9 * [PostgreSQL](https://www.postgresql.org/) -> Database
10 * [Redis](https://redis.io/) -> Job queue/cache
11 * [Express](http://expressjs.com) -> Web server framework
12 * [Sequelize](http://docs.sequelizejs.com/en/v3/) -> SQL ORM
13 * [WebTorrent](https://webtorrent.io/) -> BitTorrent tracker and torrent creation
14 * [Mocha](https://mochajs.org/) -> Test framework
15
16
17## Files
18
19The server main file is [server.ts](/server.ts).
20The server modules description are in the [package.json](/package.json) at the project root.
21All other server files are in the [server](/server) directory:
22
23 server.ts -> app initialization, main routes configuration (static routes...)
24 config -> server YAML configurations (for tests, production...)
25 scripts -> Scripts files for npm run
26 server
27 |__ controllers -> API routes/controllers files
28 |__ helpers -> functions used by different part of the project (logger, utils...)
29 |__ initializers -> functions used at the server startup (installer, database, constants...)
30 |__ lib -> library function (WebTorrent, OAuth2, ActivityPub...)
31 |__ middlewares -> middlewares for controllers (requests validators, requests pagination...)
32 |__ models -> Sequelize models for each SQL tables (videos, users, accounts...)
33 |__ tests -> API tests and real world simulations (to test the decentralized feature...)
34
35
36## Conventions
37
38Uses [JavaScript Standard Style](http://standardjs.com/).
39
40## Architecture
41
42The server is composed by:
43
44 * a REST API (relying on the Express framework) documented on http://docs.joinpeertube.org/api.html
45 * a WebTorrent Tracker (slightly custom version of [webtorrent/bittorrent-tracker](https://github.com/webtorrent/bittorrent-tracker#server))
46
47A video is seeded by the server with the [WebSeed](http://www.bittorrent.org/beps/bep_0019.html) protocol (HTTP).
48
49![Architecture scheme](/support/doc/development/server/upload-video.png)
50
51When a user uploads a video, the REST API creates the torrent file and then adds it to its database.
52
53If a user wants to watch the video, the tracker will indicate all other users that are watching the video + the HTTP url for the WebSeed.
54
55## Newcomers
56
57The server entrypoint is [server.ts](/server.ts). Looking at this file is a good start.
58Then you can try to understand the [controllers](/server/controllers): they are the entrypoints of each API request.
diff --git a/support/doc/development/server/peertube-architecture-server.xml b/support/doc/development/server/peertube-architecture-server.xml
deleted file mode 100644
index 3299307a1..000000000
--- a/support/doc/development/server/peertube-architecture-server.xml
+++ /dev/null
@@ -1 +0,0 @@
1<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36" version="7.9.7" editor="www.draw.io" type="device"><diagram id="033390a3-e8de-cf4f-5be1-41b3d99c78ae" name="Page-1">3VpRc5s4EP41nmkekgGEwH6M3aS9md5Mpnbby6MA2dBgxIHs2P31J4EECGGbxLhNzu1MYLXC0re7364Wj8BsvfuUoTT8mwQ4HllGsBuBjyPLMm3LGvH/RrAvJeOxWQpWWRQIpVowj35hITSEdBMFOFcUKSExjVJV6JMkwT5VZCjLyLOqtiSx+q0pWmFNMPdRrEt/RAENxS4sp5Z/xtEqlN9sOpNyxEP+0yojm0R838gCy+JTDq+RfJbYaB6igDw3ROBuBGYZIbS8Wu9mOObYStjKefcHRqt1ZzihfSaAcsIWxRssV1ysi+4lFsVuMNc3R2D6HEYUz1Pk89FnZn0mC+k6FsPLKI5nJCZZMVfuHUxzmpEn3Bgxig8b0VcsNrHFGcW7hkjs4BMma0yzPVMRo7YAUzgbELfPteVcqRI2rGZPhBAJb1lVT64RYxcCtG4AbQ3AbznOmMQcFsixj32/C0hvDG04EJCmpSLpmjqUlU4TSmcAJOEhJAd2yd+CJJzAP4ckGGuI4YDxm7glGQ3JiiQovqul0xpTQ8UP7yL6DxffQHH3KJQYPNm+HLKgvH8U03KKMnrLuZgJEpJgKbuP+MLFAwKp4ccozyO/FAoV/pifmNK9SBBoQwkT1ev/QkgqrUwSKtRM85gNc7LJfIGKIG22qhWWWsJuHLCjhs5wjGi0VRPGWUwinawOgFmGEWV5kC0xxEUOzIr9sIwWMaNZTsxWPQ2iLbtc8cvbIKi1tyyHkmIWz8SIIg/l1SS2msY8zV+Ym1PVDTKcR7+QVyhw26UkSmixXTgdwY9MguJolXBTsiWywAVTHi4RS6q3YmAdBUHhazHycDytUmVXwjhtT+nlWlBWZYFYrZJau4LVuDEhtJR4vRa83tvK4uEPHJWGClkuc+ZabTeo1tDLMyaaY3y9my+Y5PbhL81yL2PDAOJxYHex4djygOMMw4aTsZqg3Q4ydOCFyNC5PBmaKhm6ChkabTKsqa7Jh+Yb4EOZpJqEODgfFlPZNtG+oSDYRA+kncyfjuJCjtuqa1v6zhge02cX5QpeG5J2V+Gs03H+lBfHD17GpBhn/O7DD+x9Xcyuupl4GtFFxfJpRnwSv0tydoYi52vGzsBUCcR6Q+QsY6bhCczAlQ01n1hkDFpe1/bKwy9jc2wyPne72HziuAANxOaOc5rOJ5dic0ODaBA2tw7SeXXzWNH+eyhtTdk2aVC5/SaoHMDW0cgelpqBXkffY+qHVV3sx1FJryhNY0aBNCLJu+RYyTwDFMAGtNQEe+2Y55GsXJB0xL28b7HAICQM9B7BILTgHq7y/j+08MdOvGbHiVfGJgOOhY446eYdefRDYTCLfYnxMy//0nCz9hIUxfnNzc2B+urMDMti0+ruHgWO58CBMixo9eE6D0zuhbpHpt7SlFB6NYqlgPugAqfz74bIgeu88M5bpmDZ6a4elE+Z42yrVELl49SvYGLvBW0K1S4iCptGFKL+XN3lIIRpL+MijEOmh5OB7A5PdrJNo8PscIjKytXM/rChdTdpk8YEcbqsG0v8JDPHOLjqCE9lrl/0sfhUqtbFJ2LzMhz+Lnga6jwN+tZvjZMTdCdqWpcvQi5b40G3dWBzjtR42uzW+xz7EhWDqb9u4PUYM3GHM38hK56LLpFPIP/XlU+c4jMMr1iGWnJXJNIgFjDpIBZzkITiaFB/K8iEP7emk3bsd0XgS19LaG8legWfrcfepGfoNQCFR4j63KJaDZC2kcq9iDnHmmTqY9qVebl/7TGvCDaJ6KV7sH0puZcXgA4G7ukFQ5HrOSci+Hsgfw/JFHQE9Ntoa7fz5Mm2NrxwW9vSqLrunTDv4ERmGaLs4xXg58Xi4UrztPfQPJH5f5AG9dh1Fbtcn9k8GbY5oh/ovosK/vQpuyrYZzJTc9VLHa6xc+Bw7U68oX4tBEGPw3XXKesVtRC7rX/LVZqu/sEcuPsP</diagram></mxfile> \ No newline at end of file
diff --git a/support/doc/development/server/upload-video.png b/support/doc/development/server/upload-video.png
deleted file mode 100644
index 7edc06792..000000000
--- a/support/doc/development/server/upload-video.png
+++ /dev/null
Binary files differ
diff --git a/support/doc/production.md b/support/doc/production.md
index 2eba6e6a3..4f20cf140 100644
--- a/support/doc/production.md
+++ b/support/doc/production.md
@@ -204,6 +204,9 @@ logs. You can set another password with:
204$ cd /var/www/peertube/peertube-latest && NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run reset-password -- -u root 204$ cd /var/www/peertube/peertube-latest && NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run reset-password -- -u root
205``` 205```
206 206
207Alternatively you can set the environment variable `PT_INITIAL_ROOT_PASSWORD`,
208to your own administrator password, although it must be 6 characters or more.
209
207### What now? 210### What now?
208 211
209Now your instance is up you can: 212Now your instance is up you can:
diff --git a/support/doc/tools.md b/support/doc/tools.md
index 086cd5cff..c0f0b4ba1 100644
--- a/support/doc/tools.md
+++ b/support/doc/tools.md
@@ -35,7 +35,7 @@ You need to follow all the following steps even if you are on a PeerTube server
35 35
36### Dependencies 36### Dependencies
37 37
38Install the [PeerTube dependencies](dependencies.md). 38Install the [PeerTube dependencies](dependencies.md) except PostgreSQL and Redis.
39 39
40### Installation 40### Installation
41 41
@@ -44,18 +44,14 @@ Clone the PeerTube repo to get the latest version (even if you are on your PeerT
44``` 44```
45$ git clone https://github.com/Chocobozzz/PeerTube.git 45$ git clone https://github.com/Chocobozzz/PeerTube.git
46$ CLONE="$(pwd)/PeerTube" 46$ CLONE="$(pwd)/PeerTube"
47```
48
49Run ``yarn install --pure-lockfile``
50```
51$ cd ${CLONE} 47$ cd ${CLONE}
52$ yarn install --pure-lockfile
53``` 48```
54 49
55Build server tools: 50Install dependencies and build CLI tools:
51
56``` 52```
57$ cd ${CLONE} 53$ NOCLIENT=1 yarn install --pure-lockfile
58$ npm run build:server 54$ npm run setup:cli
59``` 55```
60 56
61### CLI wrapper 57### CLI wrapper
diff --git a/support/docker/production/.env b/support/docker/production/.env
index 7b9092642..c8393d0ce 100644
--- a/support/docker/production/.env
+++ b/support/docker/production/.env
@@ -5,8 +5,7 @@ PEERTUBE_WEBSERVER_PORT=443
5PEERTUBE_WEBSERVER_HTTPS=true 5PEERTUBE_WEBSERVER_HTTPS=true
6# If you need more than one IP as trust_proxy 6# If you need more than one IP as trust_proxy
7# pass them as a comma separated array: 7# pass them as a comma separated array:
8PEERTUBE_TRUST_PROXY=["127.0.0.1"] 8PEERTUBE_TRUST_PROXY=["127.0.0.1", "loopback", "172.18.0.0/16"]
9#PEERTUBE_TRUST_PROXY=["127.0.0.1", "loopback", "192.168.1.0/24"]
10#PEERTUBE_SMTP_USERNAME= 9#PEERTUBE_SMTP_USERNAME=
11#PEERTUBE_SMTP_PASSWORD= 10#PEERTUBE_SMTP_PASSWORD=
12PEERTUBE_SMTP_HOSTNAME=postfix 11PEERTUBE_SMTP_HOSTNAME=postfix
diff --git a/support/docker/production/config/custom-environment-variables.yaml b/support/docker/production/config/custom-environment-variables.yaml
index bd4ac1215..d5b878830 100644
--- a/support/docker/production/config/custom-environment-variables.yaml
+++ b/support/docker/production/config/custom-environment-variables.yaml
@@ -106,6 +106,9 @@ transcoding:
106 1080: 106 1080:
107 __name: "PEERTUBE_TRANSCODING_1080P" 107 __name: "PEERTUBE_TRANSCODING_1080P"
108 __format: "json" 108 __format: "json"
109 2160:
110 __name: "PEERTUBE_TRANSCODING_2160P"
111 __format: "json"
109 112
110instance: 113instance:
111 name: "PEERTUBE_INSTANCE_NAME" 114 name: "PEERTUBE_INSTANCE_NAME"
diff --git a/support/docker/production/docker-compose.yml b/support/docker/production/docker-compose.yml
index df21a14d4..263fb6e95 100644
--- a/support/docker/production/docker-compose.yml
+++ b/support/docker/production/docker-compose.yml
@@ -72,3 +72,10 @@ services:
72 labels: 72 labels:
73 traefik.enable: "false" 73 traefik.enable: "false"
74 restart: "always" 74 restart: "always"
75
76networks:
77 default:
78 ipam:
79 driver: default
80 config:
81 - subnet: 172.18.0.0/16
diff --git a/tsconfig.json b/tsconfig.json
index 5ad4b3e10..4d2bdd6ba 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -17,6 +17,7 @@
17 "typeRoots": [ "node_modules/@types", "server/typings" ] 17 "typeRoots": [ "node_modules/@types", "server/typings" ]
18 }, 18 },
19 "exclude": [ 19 "exclude": [
20 "server/tools/",
20 "client/node_modules", 21 "client/node_modules",
21 "node_modules", 22 "node_modules",
22 "dist", 23 "dist",
diff --git a/yarn.lock b/yarn.lock
index f2cc0ee05..ce086c03c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,12 +2,28 @@
2# yarn lockfile v1 2# yarn lockfile v1
3 3
4 4
5"@babel/runtime@7.0.0": 5"@babel/code-frame@^7.0.0":
6 version "7.0.0" 6 version "7.0.0"
7 resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c" 7 resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8"
8 integrity sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA== 8 integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==
9 dependencies: 9 dependencies:
10 regenerator-runtime "^0.12.0" 10 "@babel/highlight" "^7.0.0"
11
12"@babel/highlight@^7.0.0":
13 version "7.0.0"
14 resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4"
15 integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==
16 dependencies:
17 chalk "^2.0.0"
18 esutils "^2.0.2"
19 js-tokens "^4.0.0"
20
21"@babel/runtime@^7.0.0":
22 version "7.4.5"
23 resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.5.tgz#582bb531f5f9dc67d2fcb682979894f75e253f12"
24 integrity sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==
25 dependencies:
26 regenerator-runtime "^0.13.2"
11 27
12"@samverschueren/stream-to-observable@^0.3.0": 28"@samverschueren/stream-to-observable@^0.3.0":
13 version "0.3.0" 29 version "0.3.0"
@@ -28,10 +44,10 @@
28 resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.1.1.tgz#81f218213bebcc5f740efe9648272c774a2e4b4b" 44 resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.1.1.tgz#81f218213bebcc5f740efe9648272c774a2e4b4b"
29 integrity sha512-TU1X8jmAU2BjwKryBFV/GDezz7Ge0xu9ZuYC7dy6wKj4hnL0JcxeseCOr/G2JkGylff6hdUBrR+Ee5ApAQeU5g== 45 integrity sha512-TU1X8jmAU2BjwKryBFV/GDezz7Ge0xu9ZuYC7dy6wKj4hnL0JcxeseCOr/G2JkGylff6hdUBrR+Ee5ApAQeU5g==
30 46
31"@types/async@^2.0.40": 47"@types/async@^3.0.0":
32 version "2.4.1" 48 version "3.0.0"
33 resolved "https://registry.yarnpkg.com/@types/async/-/async-2.4.1.tgz#43c3b2c60eab41c25ca0009c07ca7d619d943119" 49 resolved "https://registry.yarnpkg.com/@types/async/-/async-3.0.0.tgz#d403560ee2aabccdb7936cb9a3fee5f147d626bd"
34 integrity sha512-C09BK/wXzbW+/JK9zckhe+FeSbg7NmvVjUWwApnw7ksRpUq3ecGLiq2Aw1LlY4Z/VmtdhSaIs7jO5/MWRYMcOA== 50 integrity sha512-DvEhEeG8ynipwkg7LtNHlO99+vEVbin+E+3YuzeJCM9TREewJ1B5fdZsQzykR7fKuh6rKh8mEir36zKd3uafOA==
35 51
36"@types/bcrypt@^3.0.0": 52"@types/bcrypt@^3.0.0":
37 version "3.0.0" 53 version "3.0.0"
@@ -125,17 +141,17 @@
125 "@types/express" "*" 141 "@types/express" "*"
126 142
127"@types/express-serve-static-core@*": 143"@types/express-serve-static-core@*":
128 version "4.16.2" 144 version "4.16.6"
129 resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.2.tgz#5ee8a22e602005be6767df6b2cba9879df3f75aa" 145 resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.6.tgz#66d4b29ece3e2fb6e5aac2232723002426e651bd"
130 integrity sha512-qgc8tjnDrc789rAQed8NoiFLV5VGcItA4yWNFphqGU0RcuuQngD00g3LHhWIK3HQ2XeDgVCmlNPDlqi3fWBHnQ== 146 integrity sha512-8wr3CA/EMybyb6/V8qvTRKiNkPmgUA26uA9XWD6hlA0yFDuqi4r2L0C2B0U2HAYltJamoYJszlkaWM31vrKsHg==
131 dependencies: 147 dependencies:
132 "@types/node" "*" 148 "@types/node" "*"
133 "@types/range-parser" "*" 149 "@types/range-parser" "*"
134 150
135"@types/express@*", "@types/express@^4.0.35": 151"@types/express@*", "@types/express@^4.0.35":
136 version "4.16.1" 152 version "4.17.0"
137 resolved "https://registry.yarnpkg.com/@types/express/-/express-4.16.1.tgz#d756bd1a85c34d87eaf44c888bad27ba8a4b7cf0" 153 resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.0.tgz#49eaedb209582a86f12ed9b725160f12d04ef287"
138 integrity sha512-V0clmJow23WeyblmACoxbHBu2JKlE5TiIme6Lem14FnPW9gsttyHtk6wq7njcdIWH1njAaFgR8gW09lgY98gQg== 154 integrity sha512-CjaMu57cjgjuZbh9DpkloeGxV45CnMGlVd+XpG7Gm9QgVrd7KFq+X4HY0vM+2v0bczS48Wg7bvnMY5TN+Xmcfw==
139 dependencies: 155 dependencies:
140 "@types/body-parser" "*" 156 "@types/body-parser" "*"
141 "@types/express-serve-static-core" "*" 157 "@types/express-serve-static-core" "*"
@@ -155,17 +171,17 @@
155 dependencies: 171 dependencies:
156 "@types/node" "*" 172 "@types/node" "*"
157 173
158"@types/fs-extra@^5.0.4": 174"@types/fs-extra@^7.0.0":
159 version "5.0.5" 175 version "7.0.0"
160 resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.5.tgz#080d90a792f3fa2c5559eb44bd8ef840aae9104b" 176 resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-7.0.0.tgz#9c4ad9e1339e7448a76698829def1f159c1b636c"
161 integrity sha512-w7iqhDH9mN8eLClQOYTkhdYUOSpp25eXxfc6VbFOGtzxW34JcvctH2bKjj4jD4++z4R5iO5D+pg48W2e03I65A== 177 integrity sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA==
162 dependencies: 178 dependencies:
163 "@types/node" "*" 179 "@types/node" "*"
164 180
165"@types/ioredis@*": 181"@types/ioredis@*":
166 version "4.0.10" 182 version "4.0.11"
167 resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.0.10.tgz#ca8bd95ca7d5fee32cbc5a0bf92fc29264bee237" 183 resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.0.11.tgz#4acf9d7912944bcf1e96dd6adba2f16c07ed9ae7"
168 integrity sha512-1ImAFcW5eg4f9UrftlVQPmGCkK1VyCqJ12c2wy3NlEQvzBC0GX64WlN01xj5iETqvsjczJHU+CRMPraBy9pX+g== 184 integrity sha512-spuEM4/UxlFH95NCrMojH9FTP3SLm8N2Itb9f0z0pca1IVdlPHobjps+KccEiUuYdfhzpdKOox8yGoqO9vahaw==
169 dependencies: 185 dependencies:
170 "@types/node" "*" 186 "@types/node" "*"
171 187
@@ -177,9 +193,9 @@
177 "@types/node" "*" 193 "@types/node" "*"
178 194
179"@types/lodash@^4.14.64": 195"@types/lodash@^4.14.64":
180 version "4.14.123" 196 version "4.14.133"
181 resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.123.tgz#39be5d211478c8dd3bdae98ee75bb7efe4abfe4d" 197 resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.133.tgz#430721c96da22dd1694443e68e6cec7ba1c1003d"
182 integrity sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q== 198 integrity sha512-/3JqnvPnY58GLzG3Y7fpphOhATV1DDZ/Ak3DQufjlRK5E4u+s0CfClfNFtAGBabw+jDGtRFbOZe+Z02ZMWCBNQ==
183 199
184"@types/magnet-uri@*", "@types/magnet-uri@^5.1.1": 200"@types/magnet-uri@*", "@types/magnet-uri@^5.1.1":
185 version "5.1.2" 201 version "5.1.2"
@@ -213,9 +229,9 @@
213 "@types/node" "*" 229 "@types/node" "*"
214 230
215"@types/mocha@^5.0.0": 231"@types/mocha@^5.0.0":
216 version "5.2.6" 232 version "5.2.7"
217 resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.6.tgz#b8622d50557dd155e9f2f634b7d68fd38de5e94b" 233 resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea"
218 integrity sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw== 234 integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==
219 235
220"@types/morgan@^1.7.32": 236"@types/morgan@^1.7.32":
221 version "1.7.35" 237 version "1.7.35"
@@ -232,22 +248,27 @@
232 "@types/express" "*" 248 "@types/express" "*"
233 249
234"@types/node@*": 250"@types/node@*":
235 version "11.13.0" 251 version "12.0.5"
236 resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.0.tgz#b0df8d6ef9b5001b2be3a94d909ce3c29a80f9e1" 252 resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.5.tgz#ac14404c33d1a789973c45379a67f7f7e58a01b9"
237 integrity sha512-rx29MMkRdVmzunmiA4lzBYJNnXsW/PhG4kMBy2ATsYaDjGGR75dCFEVVROKpNwlVdcUX3xxlghKQOeDPBJobng== 253 integrity sha512-CFLSALoE+93+Hcb5pFjp0J1uMrrbLRe+L1+gFwerJ776R3TACSF0kTVRQ7AvRa7aFx70nqYHAc7wQPlt9kY2Mg==
238 254
239"@types/node@^10.0.8": 255"@types/node@^10.0.8":
240 version "10.14.4" 256 version "10.14.8"
241 resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.4.tgz#1c586b991457cbb58fef51bc4e0cfcfa347714b5" 257 resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9"
242 integrity sha512-DT25xX/YgyPKiHFOpNuANIQIVvYEwCWXgK2jYYwqgaMrYE6+tq+DtmMwlD3drl6DJbUwtlIDnn0d7tIn/EbXBg== 258 integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw==
243 259
244"@types/nodemailer@^4.3.1": 260"@types/nodemailer@^6.2.0":
245 version "4.6.7" 261 version "6.2.0"
246 resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-4.6.7.tgz#ac3c594fac6daf7f71eb4d31c9e4c88b62dbcb87" 262 resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.2.0.tgz#369d3c6ff51201670f3e5469b00c1d204ec8f894"
247 integrity sha512-slR1wz8I8O20CHNBNhYhObRZ8zeG5FnfFUWLZKk1f0UDYaLZOsBjUfCC9VEFi7oSRCC886DfKmq1JncPDMOrng== 263 integrity sha512-WGGEk/BGRLuYF3gyoTwbtKg5tCexZzb5lkTsis2k7GkAzlg4x2299/SC6Ssdj3X/5TzT1BHVc8zcFg/7KSzBLw==
248 dependencies: 264 dependencies:
249 "@types/node" "*" 265 "@types/node" "*"
250 266
267"@types/normalize-package-data@^2.4.0":
268 version "2.4.0"
269 resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
270 integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
271
251"@types/oauth2-server@^3.0.8": 272"@types/oauth2-server@^3.0.8":
252 version "3.0.10" 273 version "3.0.10"
253 resolved "https://registry.yarnpkg.com/@types/oauth2-server/-/oauth2-server-3.0.10.tgz#ea671a6ad3d02062aac5f7c1ba1fb9c468314db0" 274 resolved "https://registry.yarnpkg.com/@types/oauth2-server/-/oauth2-server-3.0.10.tgz#ea671a6ad3d02062aac5f7c1ba1fb9c468314db0"
@@ -284,9 +305,9 @@
284 integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== 305 integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
285 306
286"@types/redis@*", "@types/redis@^2.8.5": 307"@types/redis@*", "@types/redis@^2.8.5":
287 version "2.8.12" 308 version "2.8.13"
288 resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.12.tgz#6405d7ece0d6cc037151b7141cef9ad3cd06f3ac" 309 resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.13.tgz#fdd76d9a8b7c36ff24d8506a94ef2a890c87f498"
289 integrity sha512-eT5cGYr08OnF6OlAHdc2hVOBAKBpfQQNQHsWEvUwRPFiXRd+vv+hOHSSIo4xB7M5vZOZdjMT2OUlXYqo3YlIGQ== 310 integrity sha512-p86cm5P6DMotUqCS6odQRz0JJwc5QXZw9eyH0ALVIqmq12yqtex5ighWyGFHKxak9vaA/GF/Ilu0KZ0MuXXUbg==
290 dependencies: 311 dependencies:
291 "@types/node" "*" 312 "@types/node" "*"
292 313
@@ -309,9 +330,9 @@
309 "@types/mime" "*" 330 "@types/mime" "*"
310 331
311"@types/sharp@^0.22.1": 332"@types/sharp@^0.22.1":
312 version "0.22.1" 333 version "0.22.2"
313 resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.22.1.tgz#4fccaa9cc580d859916bee693aa7ae7447d0e0ba" 334 resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.22.2.tgz#c9b613816ec000d94f153259b25ae41f874a75f5"
314 integrity sha512-Reri4hhX77JBx6HWt2a2CLO0xjHMFHDaeBYMslUsTSHGRFQnk+VpoH25g7/L6QzyyNNmxTekK+j+lFFjK3OkqA== 335 integrity sha512-oH49f42h3nf/qys0weYsaTGiMv67wPB769ynCoPfBAVwjjxFF3QtIPEe3MfhwyNjQAhQhTEfnmMKvVZfcFkhIw==
315 dependencies: 336 dependencies:
316 "@types/node" "*" 337 "@types/node" "*"
317 338
@@ -377,15 +398,7 @@
377 "@types/events" "*" 398 "@types/events" "*"
378 "@types/node" "*" 399 "@types/node" "*"
379 400
380JSONStream@^1.3.4, JSONStream@^1.3.5: 401abbrev@1:
381 version "1.3.5"
382 resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
383 integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
384 dependencies:
385 jsonparse "^1.2.0"
386 through ">=2.2.7 <3"
387
388abbrev@1, abbrev@~1.1.1:
389 version "1.1.1" 402 version "1.1.1"
390 resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 403 resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
391 integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== 404 integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
@@ -406,13 +419,13 @@ accepts@~1.2.12:
406 mime-types "~2.1.6" 419 mime-types "~2.1.6"
407 negotiator "0.5.3" 420 negotiator "0.5.3"
408 421
409accepts@~1.3.4, accepts@~1.3.5: 422accepts@~1.3.4, accepts@~1.3.7:
410 version "1.3.5" 423 version "1.3.7"
411 resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" 424 resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
412 integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= 425 integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
413 dependencies: 426 dependencies:
414 mime-types "~2.1.18" 427 mime-types "~2.1.24"
415 negotiator "0.6.1" 428 negotiator "0.6.2"
416 429
417acorn-jsx@^3.0.0: 430acorn-jsx@^3.0.0:
418 version "3.0.1" 431 version "3.0.1"
@@ -446,20 +459,6 @@ after@0.8.2:
446 resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" 459 resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
447 integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= 460 integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
448 461
449agent-base@4, agent-base@^4.1.0, agent-base@~4.2.1:
450 version "4.2.1"
451 resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
452 integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==
453 dependencies:
454 es6-promisify "^5.0.0"
455
456agentkeepalive@^3.4.1:
457 version "3.5.2"
458 resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67"
459 integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==
460 dependencies:
461 humanize-ms "^1.2.1"
462
463ajv-keywords@^1.0.0: 462ajv-keywords@^1.0.0:
464 version "1.5.1" 463 version "1.5.1"
465 resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" 464 resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
@@ -515,28 +514,23 @@ ansi-regex@^3.0.0:
515 resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 514 resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
516 integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 515 integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
517 516
517ansi-regex@^4.1.0:
518 version "4.1.0"
519 resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
520 integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
521
518ansi-styles@^2.2.1: 522ansi-styles@^2.2.1:
519 version "2.2.1" 523 version "2.2.1"
520 resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 524 resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
521 integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= 525 integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
522 526
523ansi-styles@^3.2.1: 527ansi-styles@^3.2.0, ansi-styles@^3.2.1:
524 version "3.2.1" 528 version "3.2.1"
525 resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 529 resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
526 integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 530 integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
527 dependencies: 531 dependencies:
528 color-convert "^1.9.0" 532 color-convert "^1.9.0"
529 533
530ansicolors@~0.3.2:
531 version "0.3.2"
532 resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979"
533 integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=
534
535ansistyles@~0.1.3:
536 version "0.1.3"
537 resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539"
538 integrity sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=
539
540any-observable@^0.3.0: 534any-observable@^0.3.0:
541 version "0.3.0" 535 version "0.3.0"
542 resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" 536 resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b"
@@ -565,34 +559,11 @@ append-field@^1.0.0:
565 resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" 559 resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
566 integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY= 560 integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=
567 561
568application-config-path@^0.1.0: 562aproba@^1.0.3:
569 version "0.1.0"
570 resolved "https://registry.yarnpkg.com/application-config-path/-/application-config-path-0.1.0.tgz#193c5f0a86541a4c66fba1e2dc38583362ea5e8f"
571 integrity sha1-GTxfCoZUGkxm+6Hi3DhYM2LqXo8=
572
573application-config@^1.0.1:
574 version "1.0.1"
575 resolved "https://registry.yarnpkg.com/application-config/-/application-config-1.0.1.tgz#5aa2e2a5ed6abd2e5d1d473d3596f574044fe9e7"
576 integrity sha1-WqLipe1qvS5dHUc9NZb1dARP6ec=
577 dependencies:
578 application-config-path "^0.1.0"
579 mkdirp "^0.5.1"
580
581aproba@^1.0.3, aproba@^1.1.1, aproba@^1.1.2:
582 version "1.2.0" 563 version "1.2.0"
583 resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" 564 resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
584 integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== 565 integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
585 566
586"aproba@^1.1.2 || 2", aproba@^2.0.0:
587 version "2.0.0"
588 resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
589 integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
590
591archy@~1.0.0:
592 version "1.0.0"
593 resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40"
594 integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=
595
596are-we-there-yet@~1.1.2: 567are-we-there-yet@~1.1.2:
597 version "1.1.5" 568 version "1.1.5"
598 resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" 569 resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
@@ -665,11 +636,6 @@ arrify@^1.0.1:
665 resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 636 resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
666 integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= 637 integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
667 638
668asap@^2.0.0:
669 version "2.0.6"
670 resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
671 integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
672
673asn1@~0.2.3: 639asn1@~0.2.3:
674 version "0.2.4" 640 version "0.2.4"
675 resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" 641 resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
@@ -698,11 +664,11 @@ assign-symbols@^1.0.0:
698 integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= 664 integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
699 665
700async-each@^1.0.1: 666async-each@^1.0.1:
701 version "1.0.2" 667 version "1.0.3"
702 resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.2.tgz#8b8a7ca2a658f927e9f307d6d1a42f4199f0f735" 668 resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
703 integrity sha512-6xrbvN0MOBKSJDdonmSSz2OwFSgxRaVtBDes26mj9KIGtDo+g9xosFRSC+i1gQh2oAN/tQ62AI/pGZGQjVOiRg== 669 integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
704 670
705async-limiter@~1.0.0: 671async-limiter@^1.0.0, async-limiter@~1.0.0:
706 version "1.0.0" 672 version "1.0.0"
707 resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" 673 resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
708 integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== 674 integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
@@ -719,7 +685,12 @@ async@1.5.1:
719 resolved "https://registry.yarnpkg.com/async/-/async-1.5.1.tgz#b05714f4b11b357bf79adaffdd06da42d0766c10" 685 resolved "https://registry.yarnpkg.com/async/-/async-1.5.1.tgz#b05714f4b11b357bf79adaffdd06da42d0766c10"
720 integrity sha1-sFcU9LEbNXv3mtr/3QbaQtB2bBA= 686 integrity sha1-sFcU9LEbNXv3mtr/3QbaQtB2bBA=
721 687
722async@>=0.2.9, async@^2.0.0, async@^2.6.1: 688async@>=0.2.9, async@^3.0.1:
689 version "3.0.1"
690 resolved "https://registry.yarnpkg.com/async/-/async-3.0.1.tgz#dfeb34657d1e63c94c0eee424297bf8a2c9a8182"
691 integrity sha512-ZswD8vwPtmBZzbn9xyi8XBQWXH3AvOQ43Za1KWYq7JeycrZuUYzx01KvHcVbXltjqH4y0MWrQ33008uLTqXuDw==
692
693async@^2.6.1:
723 version "2.6.2" 694 version "2.6.2"
724 resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" 695 resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381"
725 integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== 696 integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==
@@ -756,15 +727,6 @@ aws4@^1.8.0:
756 resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" 727 resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
757 integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== 728 integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
758 729
759babel-code-frame@^6.22.0:
760 version "6.26.0"
761 resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
762 integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
763 dependencies:
764 chalk "^1.1.3"
765 esutils "^2.0.2"
766 js-tokens "^3.0.2"
767
768backo2@1.0.2: 730backo2@1.0.2:
769 version "1.0.2" 731 version "1.0.2"
770 resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" 732 resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
@@ -817,12 +779,12 @@ bcrypt-pbkdf@^1.0.0:
817 dependencies: 779 dependencies:
818 tweetnacl "^0.14.3" 780 tweetnacl "^0.14.3"
819 781
820bcrypt@3.0.5: 782bcrypt@3.0.6:
821 version "3.0.5" 783 version "3.0.6"
822 resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-3.0.5.tgz#37a296c48ebf39fe6b28e4da3a221bf80da5aa26" 784 resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-3.0.6.tgz#f607846df62d27e60d5e795612c4f67d70206eb2"
823 integrity sha512-m4o91nB+Ce8696Ao4R3B/WtVWTc1Lszgd098/OIjU9D/URmdYwT3ooBs9uv1b97J5YhZweTq9lldPefTYZ0TwA== 785 integrity sha512-taA5bCTfXe7FUjKroKky9EXpdhkVvhE5owfxfLYodbrAR1Ul3juLmIQmIQBK4L9a5BuUcE6cqmwT+Da20lF9tg==
824 dependencies: 786 dependencies:
825 nan "2.13.1" 787 nan "2.13.2"
826 node-pre-gyp "0.12.0" 788 node-pre-gyp "0.12.0"
827 789
828bencode@^2.0.0: 790bencode@^2.0.0:
@@ -839,17 +801,6 @@ better-assert@~1.0.0:
839 dependencies: 801 dependencies:
840 callsite "1.0.0" 802 callsite "1.0.0"
841 803
842bin-links@^1.1.2:
843 version "1.1.2"
844 resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-1.1.2.tgz#fb74bd54bae6b7befc6c6221f25322ac830d9757"
845 integrity sha512-8eEHVgYP03nILphilltWjeIjMbKyJo3wvp9K816pHbhP301ismzw15mxAAEVQ/USUwcP++1uNrbERbp8lOA6Fg==
846 dependencies:
847 bluebird "^3.5.0"
848 cmd-shim "^2.0.2"
849 gentle-fs "^2.0.0"
850 graceful-fs "^4.1.11"
851 write-file-atomic "^2.3.0"
852
853binary-extensions@^1.0.0: 804binary-extensions@^1.0.0:
854 version "1.13.1" 805 version "1.13.1"
855 resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" 806 resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
@@ -860,18 +811,13 @@ binary-search@^1.3.4:
860 resolved "https://registry.yarnpkg.com/binary-search/-/binary-search-1.3.5.tgz#479ad009589e0273cf54e5d74ab1546c489078ce" 811 resolved "https://registry.yarnpkg.com/binary-search/-/binary-search-1.3.5.tgz#479ad009589e0273cf54e5d74ab1546c489078ce"
861 integrity sha512-RHFP0AdU6KAB0CCZsRMU2CJTk2EpL8GLURT+4gilpjr1f/7M91FgUMnXuQLmf3OKLet34gjuNFwO7e4agdX5pw== 812 integrity sha512-RHFP0AdU6KAB0CCZsRMU2CJTk2EpL8GLURT+4gilpjr1f/7M91FgUMnXuQLmf3OKLet34gjuNFwO7e4agdX5pw==
862 813
863bindings@^1.3.0, bindings@^1.5.0: 814bindings@^1.3.0:
864 version "1.5.0" 815 version "1.5.0"
865 resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" 816 resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
866 integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== 817 integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
867 dependencies: 818 dependencies:
868 file-uri-to-path "1.0.0" 819 file-uri-to-path "1.0.0"
869 820
870bindings@~1.2.1:
871 version "1.2.1"
872 resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11"
873 integrity sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=
874
875bindings@~1.3.0: 821bindings@~1.3.0:
876 version "1.3.1" 822 version "1.3.1"
877 resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.1.tgz#21fc7c6d67c18516ec5aaa2815b145ff77b26ea5" 823 resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.1.tgz#21fc7c6d67c18516ec5aaa2815b145ff77b26ea5"
@@ -938,16 +884,15 @@ bittorrent-protocol@^3.0.0:
938 xtend "^4.0.0" 884 xtend "^4.0.0"
939 885
940bittorrent-tracker@^9.0.0: 886bittorrent-tracker@^9.0.0:
941 version "9.10.1" 887 version "9.11.0"
942 resolved "https://registry.yarnpkg.com/bittorrent-tracker/-/bittorrent-tracker-9.10.1.tgz#5de14aac012a287af394d3cc9eda1ec6cc956f11" 888 resolved "https://registry.yarnpkg.com/bittorrent-tracker/-/bittorrent-tracker-9.11.0.tgz#9911f9c14e5a29f84990a0c31b3d83dd16eb2876"
943 integrity sha512-n5zTL/g6Wt0rb2EnkiyiaGYhth7I/N0/xMqGUpvGX/7g1scDGBVPhJnXR8lfp3/OMj681fv40o4q/otECMtZSA== 889 integrity sha512-T1zvW/kSeEnWT4I3JE+6c7aZbO5jtleZyQe911SyzIxFF9DvtUNWXud3p5ZUkXaoI2xXwfpvlks5VFj5SKEB+A==
944 dependencies: 890 dependencies:
945 bencode "^2.0.0" 891 bencode "^2.0.0"
946 bittorrent-peerid "^1.0.2" 892 bittorrent-peerid "^1.0.2"
947 bn.js "^4.4.0" 893 bn.js "^4.4.0"
948 compact2string "^1.2.0" 894 compact2string "^1.2.0"
949 debug "^3.1.0" 895 debug "^4.0.1"
950 inherits "^2.0.1"
951 ip "^1.0.1" 896 ip "^1.0.1"
952 lru "^3.0.0" 897 lru "^3.0.0"
953 minimist "^1.1.1" 898 minimist "^1.1.1"
@@ -964,7 +909,6 @@ bittorrent-tracker@^9.0.0:
964 uniq "^1.0.1" 909 uniq "^1.0.1"
965 unordered-array-remove "^1.0.2" 910 unordered-array-remove "^1.0.2"
966 ws "^6.0.0" 911 ws "^6.0.0"
967 xtend "^4.0.0"
968 optionalDependencies: 912 optionalDependencies:
969 bufferutil "^4.0.0" 913 bufferutil "^4.0.0"
970 utf-8-validate "^5.0.1" 914 utf-8-validate "^5.0.1"
@@ -1001,13 +945,6 @@ block-stream2@^1.0.0:
1001 inherits "^2.0.1" 945 inherits "^2.0.1"
1002 readable-stream "^2.0.4" 946 readable-stream "^2.0.4"
1003 947
1004block-stream@*:
1005 version "0.0.9"
1006 resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
1007 integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=
1008 dependencies:
1009 inherits "~2.0.0"
1010
1011bluebird@3.5.0: 948bluebird@3.5.0:
1012 version "3.5.0" 949 version "3.5.0"
1013 resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" 950 resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c"
@@ -1018,10 +955,10 @@ bluebird@^2.10.0:
1018 resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" 955 resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
1019 integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= 956 integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=
1020 957
1021bluebird@^3.0.5, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.3: 958bluebird@^3.0.5, bluebird@^3.5.0, bluebird@^3.5.3:
1022 version "3.5.3" 959 version "3.5.5"
1023 resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" 960 resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f"
1024 integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== 961 integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==
1025 962
1026bn.js@=2.0.4: 963bn.js@=2.0.4:
1027 version "2.0.4" 964 version "2.0.4"
@@ -1038,21 +975,21 @@ bn.js@^4.4.0:
1038 resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" 975 resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
1039 integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== 976 integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
1040 977
1041body-parser@1.18.3, body-parser@^1.12.4: 978body-parser@1.19.0, body-parser@^1.12.4:
1042 version "1.18.3" 979 version "1.19.0"
1043 resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" 980 resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
1044 integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= 981 integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
1045 dependencies: 982 dependencies:
1046 bytes "3.0.0" 983 bytes "3.1.0"
1047 content-type "~1.0.4" 984 content-type "~1.0.4"
1048 debug "2.6.9" 985 debug "2.6.9"
1049 depd "~1.1.2" 986 depd "~1.1.2"
1050 http-errors "~1.6.3" 987 http-errors "1.7.2"
1051 iconv-lite "0.4.23" 988 iconv-lite "0.4.24"
1052 on-finished "~2.3.0" 989 on-finished "~2.3.0"
1053 qs "6.5.2" 990 qs "6.7.0"
1054 raw-body "2.3.3" 991 raw-body "2.4.0"
1055 type-is "~1.6.16" 992 type-is "~1.6.17"
1056 993
1057boxen@^1.2.1: 994boxen@^1.2.1:
1058 version "1.3.0" 995 version "1.3.0"
@@ -1166,24 +1103,19 @@ builtin-modules@^1.1.1:
1166 resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 1103 resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
1167 integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= 1104 integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
1168 1105
1169builtins@^1.0.3:
1170 version "1.0.3"
1171 resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88"
1172 integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og=
1173
1174bull@^3.4.2: 1106bull@^3.4.2:
1175 version "3.7.0" 1107 version "3.10.0"
1176 resolved "https://registry.yarnpkg.com/bull/-/bull-3.7.0.tgz#ec9a8721a2cfb0421c501d28553ac1f9f025414d" 1108 resolved "https://registry.yarnpkg.com/bull/-/bull-3.10.0.tgz#5879b1201d0ed0c987fa1f42114d3dc5abf3da68"
1177 integrity sha512-DHCALp+OOahK+q2hB3sZQew0CJn4W3zYIQsdMlnBCy7JYCnJ/bdj0MFHjo5k0ZhNZxzwhLErXt1yd3llV494UQ== 1109 integrity sha512-LbQsc7c+eYd7IaJD7tS373yKLYttjTfoPZ+9xYYlPM5+gutAjofSTsESOGGyaxyX2lE1dkg+eWhUK5kAPl5Zow==
1178 dependencies: 1110 dependencies:
1179 cron-parser "^2.7.3" 1111 cron-parser "^2.7.3"
1180 debuglog "^1.0.0" 1112 debuglog "^1.0.0"
1181 get-port latest 1113 get-port "^5.0.0"
1182 ioredis "^4.5.1" 1114 ioredis "^4.5.1"
1183 lodash "^4.17.11" 1115 lodash "^4.17.11"
1184 p-timeout "^2.0.1" 1116 p-timeout "^3.1.0"
1185 promise.prototype.finally "^3.1.0" 1117 promise.prototype.finally "^3.1.0"
1186 semver "^5.6.0" 1118 semver "^6.1.1"
1187 util.promisify "^1.0.0" 1119 util.promisify "^1.0.0"
1188 uuid "^3.2.1" 1120 uuid "^3.2.1"
1189 1121
@@ -1195,46 +1127,11 @@ busboy@^0.2.11:
1195 dicer "0.2.5" 1127 dicer "0.2.5"
1196 readable-stream "1.1.x" 1128 readable-stream "1.1.x"
1197 1129
1198byline@^5.0.0: 1130bytes@3.1.0, bytes@^3.0.0:
1199 version "5.0.0"
1200 resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1"
1201 integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=
1202
1203byte-size@^5.0.1:
1204 version "5.0.1"
1205 resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-5.0.1.tgz#4b651039a5ecd96767e71a3d7ed380e48bed4191"
1206 integrity sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==
1207
1208bytes@3.0.0:
1209 version "3.0.0"
1210 resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
1211 integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
1212
1213bytes@^3.0.0:
1214 version "3.1.0" 1131 version "3.1.0"
1215 resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" 1132 resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
1216 integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== 1133 integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
1217 1134
1218cacache@^11.0.1, cacache@^11.3.2:
1219 version "11.3.2"
1220 resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.2.tgz#2d81e308e3d258ca38125b676b98b2ac9ce69bfa"
1221 integrity sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==
1222 dependencies:
1223 bluebird "^3.5.3"
1224 chownr "^1.1.1"
1225 figgy-pudding "^3.5.1"
1226 glob "^7.1.3"
1227 graceful-fs "^4.1.15"
1228 lru-cache "^5.1.1"
1229 mississippi "^3.0.0"
1230 mkdirp "^0.5.1"
1231 move-concurrently "^1.0.1"
1232 promise-inflight "^1.0.1"
1233 rimraf "^2.6.2"
1234 ssri "^6.0.1"
1235 unique-filename "^1.1.1"
1236 y18n "^4.0.0"
1237
1238cache-base@^1.0.1: 1135cache-base@^1.0.1:
1239 version "1.0.1" 1136 version "1.0.1"
1240 resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" 1137 resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
@@ -1250,11 +1147,6 @@ cache-base@^1.0.1:
1250 union-value "^1.0.0" 1147 union-value "^1.0.0"
1251 unset-value "^1.0.0" 1148 unset-value "^1.0.0"
1252 1149
1253call-limit@~1.1.0:
1254 version "1.1.0"
1255 resolved "https://registry.yarnpkg.com/call-limit/-/call-limit-1.1.0.tgz#6fd61b03f3da42a2cd0ec2b60f02bd0e71991fea"
1256 integrity sha1-b9YbA/PaQqLNDsK2DwK9DnGZH+o=
1257
1258call-me-maybe@^1.0.1: 1150call-me-maybe@^1.0.1:
1259 version "1.0.1" 1151 version "1.0.1"
1260 resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" 1152 resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
@@ -1302,9 +1194,9 @@ camelcase@^4.0.0, camelcase@^4.1.0:
1302 integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= 1194 integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
1303 1195
1304camelcase@^5.0.0: 1196camelcase@^5.0.0:
1305 version "5.3.0" 1197 version "5.3.1"
1306 resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.0.tgz#0a110882cbeba41f72f99fcf918f4a0a92a13ebf" 1198 resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
1307 integrity sha512-Y05ICatFYPAfykDIB7VdwSJ0LUl1yq/BwO2OpyGGLjiRe1fgzTwVypPiWnzkGFOVFHXrCXUNBl86bpjBhZWSJg== 1199 integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
1308 1200
1309camelize@1.0.0: 1201camelize@1.0.0:
1310 version "1.0.0" 1202 version "1.0.0"
@@ -1322,12 +1214,12 @@ caseless@~0.12.0:
1322 integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= 1214 integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
1323 1215
1324chai-json-schema@^1.5.0: 1216chai-json-schema@^1.5.0:
1325 version "1.5.0" 1217 version "1.5.1"
1326 resolved "https://registry.yarnpkg.com/chai-json-schema/-/chai-json-schema-1.5.0.tgz#6960719e40f71fd5b377c9282e5c9a46799474f6" 1218 resolved "https://registry.yarnpkg.com/chai-json-schema/-/chai-json-schema-1.5.1.tgz#d9ae4c8f8c6e24ff4d402ceddfaa865d1ca107f4"
1327 integrity sha1-aWBxnkD3H9Wzd8koLlyaRnmUdPY= 1219 integrity sha512-TR/xPDxRhqwFFCWg1HgL8nNWbpNfUwaib6pBN++QKpnd0t+o3+MBvAn5CM1mpdUMaM76oJAtUjGKdjGad01lIA==
1328 dependencies: 1220 dependencies:
1329 jsonpointer.js "0.4.0" 1221 jsonpointer.js "0.4.0"
1330 tv4 "~1.2.7" 1222 tv4 "^1.3.0"
1331 1223
1332chai-xml@^0.3.2: 1224chai-xml@^0.3.2:
1333 version "0.3.2" 1225 version "0.3.2"
@@ -1368,7 +1260,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
1368 strip-ansi "^3.0.0" 1260 strip-ansi "^3.0.0"
1369 supports-color "^2.0.0" 1261 supports-color "^2.0.0"
1370 1262
1371chalk@^2.0.1, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: 1263chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2:
1372 version "2.4.2" 1264 version "2.4.2"
1373 resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 1265 resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
1374 integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 1266 integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -1392,10 +1284,10 @@ check-error@^1.0.2:
1392 resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" 1284 resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
1393 integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= 1285 integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=
1394 1286
1395chokidar@^2.1.0: 1287chokidar@^2.1.5:
1396 version "2.1.5" 1288 version "2.1.6"
1397 resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.5.tgz#0ae8434d962281a5f56c72869e79cb6d9d86ad4d" 1289 resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5"
1398 integrity sha512-i0TprVWp+Kj4WRPtInjexJ8Q+BqTE909VpH8xVhXrJkoc5QC8VO9TryGOqTr+2hljzc1sC62t22h5tZePodM/A== 1290 integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==
1399 dependencies: 1291 dependencies:
1400 anymatch "^2.0.0" 1292 anymatch "^2.0.0"
1401 async-each "^1.0.1" 1293 async-each "^1.0.1"
@@ -1446,6 +1338,11 @@ circular-json@^0.3.1:
1446 resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" 1338 resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
1447 integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A== 1339 integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==
1448 1340
1341circular-json@^0.5.9:
1342 version "0.5.9"
1343 resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d"
1344 integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ==
1345
1449class-utils@^0.3.5: 1346class-utils@^0.3.5:
1450 version "0.3.6" 1347 version "0.3.6"
1451 resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" 1348 resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
@@ -1461,14 +1358,6 @@ cli-boxes@^1.0.0:
1461 resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" 1358 resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
1462 integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= 1359 integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
1463 1360
1464cli-columns@^3.1.2:
1465 version "3.1.2"
1466 resolved "https://registry.yarnpkg.com/cli-columns/-/cli-columns-3.1.2.tgz#6732d972979efc2ae444a1f08e08fa139c96a18e"
1467 integrity sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4=
1468 dependencies:
1469 string-width "^2.0.0"
1470 strip-ansi "^3.0.1"
1471
1472cli-cursor@^1.0.1: 1361cli-cursor@^1.0.1:
1473 version "1.0.2" 1362 version "1.0.2"
1474 resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" 1363 resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
@@ -1483,16 +1372,6 @@ cli-cursor@^2.0.0, cli-cursor@^2.1.0:
1483 dependencies: 1372 dependencies:
1484 restore-cursor "^2.0.0" 1373 restore-cursor "^2.0.0"
1485 1374
1486cli-table3@^0.5.0, cli-table3@^0.5.1:
1487 version "0.5.1"
1488 resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202"
1489 integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==
1490 dependencies:
1491 object-assign "^4.1.0"
1492 string-width "^2.1.1"
1493 optionalDependencies:
1494 colors "^1.1.2"
1495
1496cli-table@^0.3.1: 1375cli-table@^0.3.1:
1497 version "0.3.1" 1376 version "0.3.1"
1498 resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" 1377 resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23"
@@ -1522,10 +1401,14 @@ cliui@^4.0.0:
1522 strip-ansi "^4.0.0" 1401 strip-ansi "^4.0.0"
1523 wrap-ansi "^2.0.0" 1402 wrap-ansi "^2.0.0"
1524 1403
1525clone@^1.0.2: 1404cliui@^5.0.0:
1526 version "1.0.4" 1405 version "5.0.0"
1527 resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" 1406 resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
1528 integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= 1407 integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==
1408 dependencies:
1409 string-width "^3.1.0"
1410 strip-ansi "^5.2.0"
1411 wrap-ansi "^5.1.0"
1529 1412
1530closest-to@~2.0.0: 1413closest-to@~2.0.0:
1531 version "2.0.0" 1414 version "2.0.0"
@@ -1545,14 +1428,6 @@ cluster-key-slot@^1.0.6:
1545 resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.0.12.tgz#d5deff2a520717bc98313979b687309b2d368e29" 1428 resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.0.12.tgz#d5deff2a520717bc98313979b687309b2d368e29"
1546 integrity sha512-21O0kGmvED5OJ7ZTdqQ5lQQ+sjuez33R+d35jZKLwqUb5mqcPHUsxOSzj61+LHVtxGZd1kShbQM3MjB/gBJkVg== 1429 integrity sha512-21O0kGmvED5OJ7ZTdqQ5lQQ+sjuez33R+d35jZKLwqUb5mqcPHUsxOSzj61+LHVtxGZd1kShbQM3MjB/gBJkVg==
1547 1430
1548cmd-shim@^2.0.2, cmd-shim@~2.0.2:
1549 version "2.0.2"
1550 resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-2.0.2.tgz#6fcbda99483a8fd15d7d30a196ca69d688a2efdb"
1551 integrity sha1-b8vamUg6j9FdfTChlspp1oii79s=
1552 dependencies:
1553 graceful-fs "^4.1.2"
1554 mkdirp "~0.5.0"
1555
1556co-bluebird@^1.1.0: 1431co-bluebird@^1.1.0:
1557 version "1.1.0" 1432 version "1.1.0"
1558 resolved "https://registry.yarnpkg.com/co-bluebird/-/co-bluebird-1.1.0.tgz#c8b9f3a9320a7ed30987dcca1a5c3cff59655c7c" 1433 resolved "https://registry.yarnpkg.com/co-bluebird/-/co-bluebird-1.1.0.tgz#c8b9f3a9320a7ed30987dcca1a5c3cff59655c7c"
@@ -1617,10 +1492,10 @@ color@3.0.x:
1617 color-convert "^1.9.1" 1492 color-convert "^1.9.1"
1618 color-string "^1.5.2" 1493 color-string "^1.5.2"
1619 1494
1620color@^3.1.0: 1495color@^3.1.1:
1621 version "3.1.0" 1496 version "3.1.2"
1622 resolved "https://registry.yarnpkg.com/color/-/color-3.1.0.tgz#d8e9fb096732875774c84bf922815df0308d0ffc" 1497 resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10"
1623 integrity sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg== 1498 integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==
1624 dependencies: 1499 dependencies:
1625 color-convert "^1.9.1" 1500 color-convert "^1.9.1"
1626 color-string "^1.5.2" 1501 color-string "^1.5.2"
@@ -1641,25 +1516,17 @@ colors@^1.1.2, colors@^1.2.1:
1641 integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== 1516 integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==
1642 1517
1643colorspace@1.1.x: 1518colorspace@1.1.x:
1644 version "1.1.1" 1519 version "1.1.2"
1645 resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.1.tgz#9ac2491e1bc6f8fb690e2176814f8d091636d972" 1520 resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5"
1646 integrity sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw== 1521 integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==
1647 dependencies: 1522 dependencies:
1648 color "3.0.x" 1523 color "3.0.x"
1649 text-hex "1.0.x" 1524 text-hex "1.0.x"
1650 1525
1651columnify@~1.5.4:
1652 version "1.5.4"
1653 resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb"
1654 integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=
1655 dependencies:
1656 strip-ansi "^3.0.0"
1657 wcwidth "^1.0.0"
1658
1659combined-stream@^1.0.6, combined-stream@~1.0.6: 1526combined-stream@^1.0.6, combined-stream@~1.0.6:
1660 version "1.0.7" 1527 version "1.0.8"
1661 resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" 1528 resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
1662 integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== 1529 integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
1663 dependencies: 1530 dependencies:
1664 delayed-stream "~1.0.0" 1531 delayed-stream "~1.0.0"
1665 1532
@@ -1671,9 +1538,9 @@ commander@2.9.0:
1671 graceful-readlink ">= 1.0.0" 1538 graceful-readlink ">= 1.0.0"
1672 1539
1673commander@^2.12.1, commander@^2.13.0, commander@^2.14.1, commander@^2.7.1, commander@^2.8.1, commander@^2.9.0: 1540commander@^2.12.1, commander@^2.13.0, commander@^2.14.1, commander@^2.7.1, commander@^2.8.1, commander@^2.9.0:
1674 version "2.19.0" 1541 version "2.20.0"
1675 resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" 1542 resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
1676 integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== 1543 integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
1677 1544
1678compact2string@^1.2.0: 1545compact2string@^1.2.0:
1679 version "1.4.1" 1546 version "1.4.1"
@@ -1692,11 +1559,16 @@ component-emitter@1.1.2:
1692 resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" 1559 resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3"
1693 integrity sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM= 1560 integrity sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=
1694 1561
1695component-emitter@1.2.1, component-emitter@^1.2.0, component-emitter@^1.2.1: 1562component-emitter@1.2.1:
1696 version "1.2.1" 1563 version "1.2.1"
1697 resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" 1564 resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
1698 integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= 1565 integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
1699 1566
1567component-emitter@^1.2.0, component-emitter@^1.2.1:
1568 version "1.3.0"
1569 resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
1570 integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
1571
1700component-inherit@0.0.3: 1572component-inherit@0.0.3:
1701 version "0.0.3" 1573 version "0.0.3"
1702 resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" 1574 resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
@@ -1707,7 +1579,7 @@ concat-map@0.0.1:
1707 resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 1579 resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
1708 integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 1580 integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
1709 1581
1710concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.2: 1582concat-stream@^1.4.6, concat-stream@^1.5.2:
1711 version "1.6.2" 1583 version "1.6.2"
1712 resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" 1584 resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
1713 integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== 1585 integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
@@ -1717,7 +1589,7 @@ concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.2:
1717 readable-stream "^2.2.2" 1589 readable-stream "^2.2.2"
1718 typedarray "^0.0.6" 1590 typedarray "^0.0.6"
1719 1591
1720concurrently@^4.0.1: 1592concurrently@^4.1.0:
1721 version "4.1.0" 1593 version "4.1.0"
1722 resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-4.1.0.tgz#17fdf067da71210685d9ea554423ef239da30d33" 1594 resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-4.1.0.tgz#17fdf067da71210685d9ea554423ef239da30d33"
1723 integrity sha512-pwzXCE7qtOB346LyO9eFWpkFJVO3JQZ/qU/feGeaAHiX1M3Rw3zgXKc5cZ8vSH5DGygkjzLFDzA/pwoQDkRNGg== 1595 integrity sha512-pwzXCE7qtOB346LyO9eFWpkFJVO3JQZ/qU/feGeaAHiX1M3Rw3zgXKc5cZ8vSH5DGygkjzLFDzA/pwoQDkRNGg==
@@ -1732,18 +1604,10 @@ concurrently@^4.0.1:
1732 tree-kill "^1.1.0" 1604 tree-kill "^1.1.0"
1733 yargs "^12.0.1" 1605 yargs "^12.0.1"
1734 1606
1735config-chain@^1.1.12:
1736 version "1.1.12"
1737 resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa"
1738 integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==
1739 dependencies:
1740 ini "^1.3.4"
1741 proto-list "~1.2.1"
1742
1743config@^3.0.0: 1607config@^3.0.0:
1744 version "3.0.1" 1608 version "3.1.0"
1745 resolved "https://registry.yarnpkg.com/config/-/config-3.0.1.tgz#c3118e2eb45fdfd135277339f87e2492559cb147" 1609 resolved "https://registry.yarnpkg.com/config/-/config-3.1.0.tgz#c7d49c4171e8f6cb61c1d69e22647ffd60492548"
1746 integrity sha512-TBNrrk2b6AybUohqXw2AydglFBL9b/+1GG93Di6Fm6x1SyVJ5PYgo+mqY2X0KpU9m0PJDSbFaC5H95utSphtLw== 1610 integrity sha512-t6oDeNQbsIWa+D/KF4959TANzjSHLv1BA/hvL8tHEA3OUSWgBXELKaONSI6nr9oanbKs0DXonjOWLcrtZ3yTAA==
1747 dependencies: 1611 dependencies:
1748 json5 "^1.0.1" 1612 json5 "^1.0.1"
1749 1613
@@ -1759,7 +1623,7 @@ configstore@^3.0.0:
1759 write-file-atomic "^2.0.0" 1623 write-file-atomic "^2.0.0"
1760 xdg-basedir "^3.0.0" 1624 xdg-basedir "^3.0.0"
1761 1625
1762console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: 1626console-control-strings@^1.0.0, console-control-strings@~1.1.0:
1763 version "1.1.0" 1627 version "1.1.0"
1764 resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 1628 resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
1765 integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= 1629 integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
@@ -1769,10 +1633,12 @@ content-disposition@0.5.1:
1769 resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" 1633 resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b"
1770 integrity sha1-h0dsamfI2qh+Muh2Ft+IO6f7Bxs= 1634 integrity sha1-h0dsamfI2qh+Muh2Ft+IO6f7Bxs=
1771 1635
1772content-disposition@0.5.2: 1636content-disposition@0.5.3:
1773 version "0.5.2" 1637 version "0.5.3"
1774 resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 1638 resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
1775 integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= 1639 integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
1640 dependencies:
1641 safe-buffer "5.1.2"
1776 1642
1777content-security-policy-builder@2.0.0: 1643content-security-policy-builder@2.0.0:
1778 version "2.0.0" 1644 version "2.0.0"
@@ -1807,32 +1673,25 @@ cookie@0.3.1:
1807 resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" 1673 resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
1808 integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= 1674 integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
1809 1675
1676cookie@0.4.0:
1677 version "0.4.0"
1678 resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
1679 integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
1680
1810cookiejar@^2.1.0: 1681cookiejar@^2.1.0:
1811 version "2.1.2" 1682 version "2.1.2"
1812 resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" 1683 resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c"
1813 integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== 1684 integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==
1814 1685
1815copy-concurrently@^1.0.0:
1816 version "1.0.5"
1817 resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
1818 integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==
1819 dependencies:
1820 aproba "^1.1.1"
1821 fs-write-stream-atomic "^1.0.8"
1822 iferr "^0.1.5"
1823 mkdirp "^0.5.1"
1824 rimraf "^2.5.4"
1825 run-queue "^1.0.0"
1826
1827copy-descriptor@^0.1.0: 1686copy-descriptor@^0.1.0:
1828 version "0.1.1" 1687 version "0.1.1"
1829 resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" 1688 resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
1830 integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= 1689 integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
1831 1690
1832core-js@^2.5.7: 1691core-js@^2.5.7:
1833 version "2.6.5" 1692 version "2.6.9"
1834 resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" 1693 resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
1835 integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== 1694 integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
1836 1695
1837core-util-is@1.0.2, core-util-is@~1.0.0: 1696core-util-is@1.0.2, core-util-is@~1.0.0:
1838 version "1.0.2" 1697 version "1.0.2"
@@ -1847,14 +1706,14 @@ cors@^2.8.1:
1847 object-assign "^4" 1706 object-assign "^4"
1848 vary "^1" 1707 vary "^1"
1849 1708
1850cosmiconfig@^5.0.2, cosmiconfig@^5.0.7: 1709cosmiconfig@^5.2.0:
1851 version "5.2.0" 1710 version "5.2.1"
1852 resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.0.tgz#45038e4d28a7fe787203aede9c25bca4a08b12c8" 1711 resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
1853 integrity sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g== 1712 integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==
1854 dependencies: 1713 dependencies:
1855 import-fresh "^2.0.0" 1714 import-fresh "^2.0.0"
1856 is-directory "^0.3.1" 1715 is-directory "^0.3.1"
1857 js-yaml "^3.13.0" 1716 js-yaml "^3.13.1"
1858 parse-json "^4.0.0" 1717 parse-json "^4.0.0"
1859 1718
1860create-error-class@^3.0.0: 1719create-error-class@^3.0.0:
@@ -1884,9 +1743,9 @@ create-torrent@^3.24.5, create-torrent@^3.33.0:
1884 simple-sha1 "^2.0.0" 1743 simple-sha1 "^2.0.0"
1885 1744
1886cron-parser@^2.7.3: 1745cron-parser@^2.7.3:
1887 version "2.10.0" 1746 version "2.11.0"
1888 resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.10.0.tgz#d6bed39cfa6163930f89b1ade82df7b46f52b82b" 1747 resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.11.0.tgz#c3bf477e01de6a56938d6625b92efd6cec30a8a5"
1889 integrity sha512-E181Gbg+wYT0hSikwBOokL7VHgJDYUlFsRFHIlnTP8GGefhcIyf8PSc2IXztmghj5mhAZupU0n3jKfEpZVEmVg== 1748 integrity sha512-L5LAGlvq2xmCLErhjQRX8IL5v72y8jhGOaxrarYOhse0kJjJGb/vY/0sV/c7F/SylJGkUIY2iZPPJXZD3glZqA==
1890 dependencies: 1749 dependencies:
1891 is-nan "^1.2.1" 1750 is-nan "^1.2.1"
1892 moment-timezone "^0.5.23" 1751 moment-timezone "^0.5.23"
@@ -1926,11 +1785,6 @@ cycle@1.0.x:
1926 resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" 1785 resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2"
1927 integrity sha1-IegLK+hYD5i0aPN5QwZisEbDStI= 1786 integrity sha1-IegLK+hYD5i0aPN5QwZisEbDStI=
1928 1787
1929cyclist@~0.2.2:
1930 version "0.2.2"
1931 resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
1932 integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=
1933
1934d@1: 1788d@1:
1935 version "1.0.0" 1789 version "1.0.0"
1936 resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" 1790 resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
@@ -1955,14 +1809,6 @@ date-fns@^1.23.0, date-fns@^1.27.2:
1955 resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" 1809 resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
1956 integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== 1810 integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
1957 1811
1958deasync@^0.1.4:
1959 version "0.1.14"
1960 resolved "https://registry.yarnpkg.com/deasync/-/deasync-0.1.14.tgz#232ea2252b443948cad033d792eb3b24b0a3d828"
1961 integrity sha512-wN8sIuEqIwyQh72AG7oY6YQODCxIp1eXzEZlZznBuwDF8Q03Tdy9QNp1BNZXeadXoklNrw+Ip1fch+KXo/+ASw==
1962 dependencies:
1963 bindings "~1.2.1"
1964 node-addon-api "^1.6.0"
1965
1966debug@2.2.0, debug@~2.2.0: 1812debug@2.2.0, debug@~2.2.0:
1967 version "2.2.0" 1813 version "2.2.0"
1968 resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" 1814 resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da"
@@ -1977,21 +1823,14 @@ debug@2.3.3:
1977 dependencies: 1823 dependencies:
1978 ms "0.7.2" 1824 ms "0.7.2"
1979 1825
1980debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: 1826debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.3.3:
1981 version "2.6.9" 1827 version "2.6.9"
1982 resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 1828 resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
1983 integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 1829 integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
1984 dependencies: 1830 dependencies:
1985 ms "2.0.0" 1831 ms "2.0.0"
1986 1832
1987debug@3.1.0, debug@~3.1.0: 1833debug@3.2.6, debug@^3.1.0, debug@^3.2.6:
1988 version "3.1.0"
1989 resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
1990 integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
1991 dependencies:
1992 ms "2.0.0"
1993
1994debug@3.2.6, debug@^3.1.0:
1995 version "3.2.6" 1834 version "3.2.6"
1996 resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 1835 resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
1997 integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 1836 integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
@@ -2005,12 +1844,19 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0:
2005 dependencies: 1844 dependencies:
2006 ms "^2.1.1" 1845 ms "^2.1.1"
2007 1846
2008debuglog@^1.0.0, debuglog@^1.0.1: 1847debug@~3.1.0:
1848 version "3.1.0"
1849 resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
1850 integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
1851 dependencies:
1852 ms "2.0.0"
1853
1854debuglog@^1.0.0:
2009 version "1.0.1" 1855 version "1.0.1"
2010 resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" 1856 resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
2011 integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= 1857 integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
2012 1858
2013decamelize@^1.1.1, decamelize@^1.2.0: 1859decamelize@^1.2.0:
2014 version "1.2.0" 1860 version "1.2.0"
2015 resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 1861 resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
2016 integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= 1862 integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
@@ -2066,13 +1912,6 @@ deep-object-diff@^1.1.0:
2066 resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a" 1912 resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a"
2067 integrity sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw== 1913 integrity sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw==
2068 1914
2069defaults@^1.0.3:
2070 version "1.0.3"
2071 resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"
2072 integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=
2073 dependencies:
2074 clone "^1.0.2"
2075
2076define-properties@^1.1.1, define-properties@^1.1.2: 1915define-properties@^1.1.1, define-properties@^1.1.2:
2077 version "1.1.3" 1916 version "1.1.3"
2078 resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 1917 resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
@@ -2130,9 +1969,9 @@ delegates@^1.0.0:
2130 integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= 1969 integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
2131 1970
2132denque@^1.1.0: 1971denque@^1.1.0:
2133 version "1.4.0" 1972 version "1.4.1"
2134 resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.0.tgz#79e2f0490195502107f24d9553f374837dabc916" 1973 resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf"
2135 integrity sha512-gh513ac7aiKrAgjiIBWZG0EASyDF9p4JMWwKA8YU5s9figrL5SRNEMT6FDynsegakuhWd1wVqTvqvqAoDxw7wQ== 1974 integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==
2136 1975
2137depd@2.0.0: 1976depd@2.0.0:
2138 version "2.0.0" 1977 version "2.0.0"
@@ -2144,46 +1983,16 @@ depd@~1.1.0, depd@~1.1.2:
2144 resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 1983 resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
2145 integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 1984 integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
2146 1985
2147descrevit@^0.1.1:
2148 version "0.1.1"
2149 resolved "https://registry.yarnpkg.com/descrevit/-/descrevit-0.1.1.tgz#c0f5840de0a0f7b1b8b4078569b173327947d5da"
2150 integrity sha1-wPWEDeCg97G4tAeFabFzMnlH1do=
2151 dependencies:
2152 deasync "^0.1.4"
2153
2154destroy@~1.0.4: 1986destroy@~1.0.4:
2155 version "1.0.4" 1987 version "1.0.4"
2156 resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 1988 resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
2157 integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 1989 integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
2158 1990
2159detect-file@^1.0.0:
2160 version "1.0.0"
2161 resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
2162 integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
2163
2164detect-indent@~5.0.0:
2165 version "5.0.0"
2166 resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d"
2167 integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50=
2168
2169detect-libc@^1.0.2, detect-libc@^1.0.3: 1991detect-libc@^1.0.2, detect-libc@^1.0.3:
2170 version "1.0.3" 1992 version "1.0.3"
2171 resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 1993 resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
2172 integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= 1994 integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
2173 1995
2174detect-newline@^2.1.0:
2175 version "2.1.0"
2176 resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2"
2177 integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=
2178
2179dezalgo@^1.0.0, dezalgo@~1.0.3:
2180 version "1.0.3"
2181 resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456"
2182 integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=
2183 dependencies:
2184 asap "^2.0.0"
2185 wrappy "1"
2186
2187diagnostics@^1.1.1: 1996diagnostics@^1.1.1:
2188 version "1.1.1" 1997 version "1.1.1"
2189 resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a" 1998 resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a"
@@ -2201,21 +2010,21 @@ dicer@0.2.5:
2201 readable-stream "1.1.x" 2010 readable-stream "1.1.x"
2202 streamsearch "0.1.2" 2011 streamsearch "0.1.2"
2203 2012
2204diff@3.5.0, diff@^3.1.0, diff@^3.2.0: 2013diff@3.5.0, diff@^3.2.0:
2205 version "3.5.0" 2014 version "3.5.0"
2206 resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 2015 resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
2207 integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== 2016 integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
2208 2017
2018diff@^4.0.1:
2019 version "4.0.1"
2020 resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff"
2021 integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==
2022
2209dns-prefetch-control@0.1.0: 2023dns-prefetch-control@0.1.0:
2210 version "0.1.0" 2024 version "0.1.0"
2211 resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz#60ddb457774e178f1f9415f0cabb0e85b0b300b2" 2025 resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz#60ddb457774e178f1f9415f0cabb0e85b0b300b2"
2212 integrity sha1-YN20V3dOF48flBXwyrsOhbCzALI= 2026 integrity sha1-YN20V3dOF48flBXwyrsOhbCzALI=
2213 2027
2214docopt@~0.6.2:
2215 version "0.6.2"
2216 resolved "https://registry.yarnpkg.com/docopt/-/docopt-0.6.2.tgz#b28e9e2220da5ec49f7ea5bb24a47787405eeb11"
2217 integrity sha1-so6eIiDaXsSffqW7JKR3h0Be6xE=
2218
2219doctrine@0.7.2: 2028doctrine@0.7.2:
2220 version "0.7.2" 2029 version "0.7.2"
2221 resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523" 2030 resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523"
@@ -2237,14 +2046,6 @@ dont-sniff-mimetype@1.0.0:
2237 resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58" 2046 resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58"
2238 integrity sha1-WTKJDcn04vGeXrAqIAJuXl78j1g= 2047 integrity sha1-WTKJDcn04vGeXrAqIAJuXl78j1g=
2239 2048
2240dot-json@^1.0.3:
2241 version "1.1.0"
2242 resolved "https://registry.yarnpkg.com/dot-json/-/dot-json-1.1.0.tgz#36dc7d40c00afaef2823b715b94325ba39f1bd89"
2243 integrity sha512-PiQZW9/C8xILPYK2bOye/cbPZrakNEkt28jFb8RlPCwsoMAHYYw9T8JoACxgttHL9Y2AmdqVvibbZJHtLgeqTQ==
2244 dependencies:
2245 docopt "~0.6.2"
2246 underscore-keypath "~0.0.22"
2247
2248dot-prop@^4.1.0: 2049dot-prop@^4.1.0:
2249 version "4.2.0" 2050 version "4.2.0"
2250 resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" 2051 resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
@@ -2252,11 +2053,6 @@ dot-prop@^4.1.0:
2252 dependencies: 2053 dependencies:
2253 is-obj "^1.0.0" 2054 is-obj "^1.0.0"
2254 2055
2255dotenv@^5.0.1:
2256 version "5.0.1"
2257 resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef"
2258 integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==
2259
2260dottie@^2.0.0: 2056dottie@^2.0.0:
2261 version "2.0.1" 2057 version "2.0.1"
2262 resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.1.tgz#697ad9d72004db7574d21f892466a3c285893659" 2058 resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.1.tgz#697ad9d72004db7574d21f892466a3c285893659"
@@ -2272,7 +2068,7 @@ duplexer3@^0.1.4:
2272 resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" 2068 resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
2273 integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= 2069 integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
2274 2070
2275duplexify@^3.2.0, duplexify@^3.4.2, duplexify@^3.5.0, duplexify@^3.6.0: 2071duplexify@^3.2.0, duplexify@^3.5.0, duplexify@^3.6.0:
2276 version "3.7.1" 2072 version "3.7.1"
2277 resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" 2073 resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
2278 integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== 2074 integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
@@ -2297,11 +2093,6 @@ ecdsa-sig-formatter@1.0.11:
2297 dependencies: 2093 dependencies:
2298 safe-buffer "^5.0.1" 2094 safe-buffer "^5.0.1"
2299 2095
2300editor@~1.0.0:
2301 version "1.0.0"
2302 resolved "https://registry.yarnpkg.com/editor/-/editor-1.0.0.tgz#60c7f87bd62bcc6a894fa8ccd6afb7823a24f742"
2303 integrity sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=
2304
2305ee-first@1.1.1: 2096ee-first@1.1.1:
2306 version "1.1.1" 2097 version "1.1.1"
2307 resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 2098 resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -2322,6 +2113,11 @@ elliptic@=3.0.3:
2322 hash.js "^1.0.0" 2113 hash.js "^1.0.0"
2323 inherits "^2.0.1" 2114 inherits "^2.0.1"
2324 2115
2116emoji-regex@^7.0.1:
2117 version "7.0.3"
2118 resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
2119 integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
2120
2325enabled@1.0.x: 2121enabled@1.0.x:
2326 version "1.0.2" 2122 version "1.0.2"
2327 resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93" 2123 resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93"
@@ -2334,7 +2130,7 @@ encodeurl@~1.0.2:
2334 resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 2130 resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
2335 integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 2131 integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
2336 2132
2337encoding@^0.1.11, encoding@^0.1.12, encoding@~0.1.12: 2133encoding@^0.1.12, encoding@~0.1.12:
2338 version "0.1.12" 2134 version "0.1.12"
2339 resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" 2135 resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
2340 integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= 2136 integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=
@@ -2435,18 +2231,6 @@ env-variable@0.0.x:
2435 resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88" 2231 resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88"
2436 integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA== 2232 integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==
2437 2233
2438err-code@^1.0.0:
2439 version "1.1.2"
2440 resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960"
2441 integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=
2442
2443errno@~0.1.7:
2444 version "0.1.7"
2445 resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
2446 integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
2447 dependencies:
2448 prr "~1.0.1"
2449
2450error-ex@^1.3.1: 2234error-ex@^1.3.1:
2451 version "1.3.2" 2235 version "1.3.2"
2452 resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 2236 resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
@@ -2476,9 +2260,9 @@ es-to-primitive@^1.2.0:
2476 is-symbol "^1.0.2" 2260 is-symbol "^1.0.2"
2477 2261
2478es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: 2262es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
2479 version "0.10.49" 2263 version "0.10.50"
2480 resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.49.tgz#059a239de862c94494fec28f8150c977028c6c5e" 2264 resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.50.tgz#6d0e23a0abdb27018e5ac4fd09b412bc5517a778"
2481 integrity sha512-3NMEhi57E31qdzmYp2jwRArIUsj1HI/RxbQ4bgnSB+AIKIxsAmTiK83bYMifIcpWvEc3P1X30DhUKOqEtF/kvg== 2265 integrity sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==
2482 dependencies: 2266 dependencies:
2483 es6-iterator "~2.0.3" 2267 es6-iterator "~2.0.3"
2484 es6-symbol "~3.1.1" 2268 es6-symbol "~3.1.1"
@@ -2505,18 +2289,6 @@ es6-map@^0.1.3:
2505 es6-symbol "~3.1.1" 2289 es6-symbol "~3.1.1"
2506 event-emitter "~0.3.5" 2290 event-emitter "~0.3.5"
2507 2291
2508es6-promise@^4.0.3:
2509 version "4.2.6"
2510 resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f"
2511 integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==
2512
2513es6-promisify@^5.0.0:
2514 version "5.0.0"
2515 resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
2516 integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
2517 dependencies:
2518 es6-promise "^4.0.3"
2519
2520es6-promisify@^6.0.0: 2292es6-promisify@^6.0.0:
2521 version "6.0.1" 2293 version "6.0.1"
2522 resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.1.tgz#6edaa45f3bd570ffe08febce66f7116be4b1cdb6" 2294 resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.1.tgz#6edaa45f3bd570ffe08febce66f7116be4b1cdb6"
@@ -2725,17 +2497,10 @@ expand-template@^2.0.3:
2725 resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" 2497 resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
2726 integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== 2498 integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
2727 2499
2728expand-tilde@^2.0.0, expand-tilde@^2.0.2: 2500expect-ct@0.2.0:
2729 version "2.0.2" 2501 version "0.2.0"
2730 resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" 2502 resolved "https://registry.yarnpkg.com/expect-ct/-/expect-ct-0.2.0.tgz#3a54741b6ed34cc7a93305c605f63cd268a54a62"
2731 integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= 2503 integrity sha512-6SK3MG/Bbhm8MsgyJAylg+ucIOU71/FzyFalcfu5nY19dH8y/z0tBJU0wrNBXD4B27EoQtqPF/9wqH0iYAd04g==
2732 dependencies:
2733 homedir-polyfill "^1.0.1"
2734
2735expect-ct@0.1.1:
2736 version "0.1.1"
2737 resolved "https://registry.yarnpkg.com/expect-ct/-/expect-ct-0.1.1.tgz#de84476a2dbcb85000d5903737e9bc8a5ba7b897"
2738 integrity sha512-ngXzTfoRGG7fYens3/RMb6yYoVLvLMfmsSllP/mZPxNHgFq41TmPSLF/nLY7fwoclI2vElvAmILFWGUYqdjfCg==
2739 2504
2740express-oauth-server@^2.0.0: 2505express-oauth-server@^2.0.0:
2741 version "2.0.0" 2506 version "2.0.0"
@@ -2746,12 +2511,10 @@ express-oauth-server@^2.0.0:
2746 express "^4.13.3" 2511 express "^4.13.3"
2747 oauth2-server "3.0.0" 2512 oauth2-server "3.0.0"
2748 2513
2749express-rate-limit@^3.1.0: 2514express-rate-limit@^4.0.4:
2750 version "3.4.0" 2515 version "4.0.4"
2751 resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-3.4.0.tgz#c053ee294feac6d3529863de549438749fd83ef1" 2516 resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-4.0.4.tgz#a495338ae9e58c856b66d1346ec0d86f43ba2e43"
2752 integrity sha512-SktWQGHhTQfIOZykiVIaoqmHCptqq177fEbumVytWsMpEqe+g78IFrfzivJTimoCdMZ5+vYJ5/a/w1darXMv+A== 2517 integrity sha512-DLRj2vMO7Xgai8qWKU9O6ZztF2bdDmfFNFi9k3G9BPzJ+7MG7eWaaBikbe0eBpNGSxU8JziwW0PQKG78aNWa6g==
2753 dependencies:
2754 defaults "^1.0.3"
2755 2518
2756express-validator@^5.0.0: 2519express-validator@^5.0.0:
2757 version "5.3.1" 2520 version "5.3.1"
@@ -2793,38 +2556,38 @@ express@4.13.4:
2793 vary "~1.0.1" 2556 vary "~1.0.1"
2794 2557
2795express@^4.12.4, express@^4.13.3: 2558express@^4.12.4, express@^4.13.3:
2796 version "4.16.4" 2559 version "4.17.1"
2797 resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" 2560 resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
2798 integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== 2561 integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
2799 dependencies: 2562 dependencies:
2800 accepts "~1.3.5" 2563 accepts "~1.3.7"
2801 array-flatten "1.1.1" 2564 array-flatten "1.1.1"
2802 body-parser "1.18.3" 2565 body-parser "1.19.0"
2803 content-disposition "0.5.2" 2566 content-disposition "0.5.3"
2804 content-type "~1.0.4" 2567 content-type "~1.0.4"
2805 cookie "0.3.1" 2568 cookie "0.4.0"
2806 cookie-signature "1.0.6" 2569 cookie-signature "1.0.6"
2807 debug "2.6.9" 2570 debug "2.6.9"
2808 depd "~1.1.2" 2571 depd "~1.1.2"
2809 encodeurl "~1.0.2" 2572 encodeurl "~1.0.2"
2810 escape-html "~1.0.3" 2573 escape-html "~1.0.3"
2811 etag "~1.8.1" 2574 etag "~1.8.1"
2812 finalhandler "1.1.1" 2575 finalhandler "~1.1.2"
2813 fresh "0.5.2" 2576 fresh "0.5.2"
2814 merge-descriptors "1.0.1" 2577 merge-descriptors "1.0.1"
2815 methods "~1.1.2" 2578 methods "~1.1.2"
2816 on-finished "~2.3.0" 2579 on-finished "~2.3.0"
2817 parseurl "~1.3.2" 2580 parseurl "~1.3.3"
2818 path-to-regexp "0.1.7" 2581 path-to-regexp "0.1.7"
2819 proxy-addr "~2.0.4" 2582 proxy-addr "~2.0.5"
2820 qs "6.5.2" 2583 qs "6.7.0"
2821 range-parser "~1.2.0" 2584 range-parser "~1.2.1"
2822 safe-buffer "5.1.2" 2585 safe-buffer "5.1.2"
2823 send "0.16.2" 2586 send "0.17.1"
2824 serve-static "1.13.2" 2587 serve-static "1.14.1"
2825 setprototypeof "1.1.0" 2588 setprototypeof "1.1.1"
2826 statuses "~1.4.0" 2589 statuses "~1.5.0"
2827 type-is "~1.6.16" 2590 type-is "~1.6.18"
2828 utils-merge "1.0.1" 2591 utils-merge "1.0.1"
2829 vary "~1.1.2" 2592 vary "~1.1.2"
2830 2593
@@ -2897,21 +2660,16 @@ fast-safe-stringify@^2.0.4:
2897 resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz#04b26106cc56681f51a044cfc0d76cf0008ac2c2" 2660 resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz#04b26106cc56681f51a044cfc0d76cf0008ac2c2"
2898 integrity sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg== 2661 integrity sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==
2899 2662
2900feature-policy@0.2.0: 2663feature-policy@0.3.0:
2901 version "0.2.0" 2664 version "0.3.0"
2902 resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.2.0.tgz#22096de49ab240176878ffe2bde2f6ff04d48c43" 2665 resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.3.0.tgz#7430e8e54a40da01156ca30aaec1a381ce536069"
2903 integrity sha512-2hGrlv6efG4hscYVZeaYjpzpT6I2OZgYqE2yDUzeAcKj2D1SH0AsEzqJNXzdoglEddcIXQQYop3lD97XpG75Jw== 2666 integrity sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==
2904 2667
2905fecha@^2.3.3: 2668fecha@^2.3.3:
2906 version "2.3.3" 2669 version "2.3.3"
2907 resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd" 2670 resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
2908 integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg== 2671 integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
2909 2672
2910figgy-pudding@^3.4.1, figgy-pudding@^3.5.1:
2911 version "3.5.1"
2912 resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
2913 integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==
2914
2915figures@^1.3.5, figures@^1.7.0: 2673figures@^1.3.5, figures@^1.7.0:
2916 version "1.7.0" 2674 version "1.7.0"
2917 resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" 2675 resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
@@ -2970,52 +2728,32 @@ finalhandler@0.4.1:
2970 on-finished "~2.3.0" 2728 on-finished "~2.3.0"
2971 unpipe "~1.0.0" 2729 unpipe "~1.0.0"
2972 2730
2973finalhandler@1.1.1: 2731finalhandler@~1.1.2:
2974 version "1.1.1" 2732 version "1.1.2"
2975 resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" 2733 resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
2976 integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== 2734 integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
2977 dependencies: 2735 dependencies:
2978 debug "2.6.9" 2736 debug "2.6.9"
2979 encodeurl "~1.0.2" 2737 encodeurl "~1.0.2"
2980 escape-html "~1.0.3" 2738 escape-html "~1.0.3"
2981 on-finished "~2.3.0" 2739 on-finished "~2.3.0"
2982 parseurl "~1.3.2" 2740 parseurl "~1.3.3"
2983 statuses "~1.4.0" 2741 statuses "~1.5.0"
2984 unpipe "~1.0.0" 2742 unpipe "~1.0.0"
2985 2743
2986find-npm-prefix@^1.0.2: 2744find-up@3.0.0, find-up@^3.0.0:
2987 version "1.0.2"
2988 resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf"
2989 integrity sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==
2990
2991find-parent-dir@^0.3.0:
2992 version "0.3.0"
2993 resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54"
2994 integrity sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=
2995
2996find-up@^2.1.0:
2997 version "2.1.0"
2998 resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
2999 integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
3000 dependencies:
3001 locate-path "^2.0.0"
3002
3003find-up@^3.0.0:
3004 version "3.0.0" 2745 version "3.0.0"
3005 resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" 2746 resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
3006 integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== 2747 integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
3007 dependencies: 2748 dependencies:
3008 locate-path "^3.0.0" 2749 locate-path "^3.0.0"
3009 2750
3010findup-sync@2.0.0: 2751find-up@^4.0.0:
3011 version "2.0.0" 2752 version "4.0.0"
3012 resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" 2753 resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.0.0.tgz#c367f8024de92efb75f2d4906536d24682065c3a"
3013 integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw= 2754 integrity sha512-zoH7ZWPkRdgwYCDVoQTzqjG8JSPANhtvLhh4KVUHyKnaUJJrNeFmWIkTcNuJmR3GLMEmGYEf2S2bjgx26JTF+Q==
3014 dependencies: 2755 dependencies:
3015 detect-file "^1.0.0" 2756 locate-path "^5.0.0"
3016 is-glob "^3.1.0"
3017 micromatch "^3.0.4"
3018 resolve-dir "^1.0.1"
3019 2757
3020flat-cache@^1.2.1: 2758flat-cache@^1.2.1:
3021 version "1.3.4" 2759 version "1.3.4"
@@ -3039,11 +2777,6 @@ flatten@^1.0.2:
3039 resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" 2777 resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
3040 integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I= 2778 integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=
3041 2779
3042flexbuffer@0.0.6:
3043 version "0.0.6"
3044 resolved "https://registry.yarnpkg.com/flexbuffer/-/flexbuffer-0.0.6.tgz#039fdf23f8823e440c38f3277e6fef1174215b30"
3045 integrity sha1-A5/fI/iCPkQMOPMnfm/vEXQhWzA=
3046
3047fluent-ffmpeg@^2.1.0: 2780fluent-ffmpeg@^2.1.0:
3048 version "2.1.2" 2781 version "2.1.2"
3049 resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74" 2782 resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74"
@@ -3052,14 +2785,6 @@ fluent-ffmpeg@^2.1.0:
3052 async ">=0.2.9" 2785 async ">=0.2.9"
3053 which "^1.1.1" 2786 which "^1.1.1"
3054 2787
3055flush-write-stream@^1.0.0:
3056 version "1.1.1"
3057 resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
3058 integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==
3059 dependencies:
3060 inherits "^2.0.3"
3061 readable-stream "^2.3.6"
3062
3063fn-name@~2.0.1: 2788fn-name@~2.0.1:
3064 version "2.0.1" 2789 version "2.0.1"
3065 resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7" 2790 resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7"
@@ -3106,10 +2831,10 @@ fragment-cache@^0.2.1:
3106 dependencies: 2831 dependencies:
3107 map-cache "^0.2.2" 2832 map-cache "^0.2.2"
3108 2833
3109frameguard@3.0.0: 2834frameguard@3.1.0:
3110 version "3.0.0" 2835 version "3.1.0"
3111 resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.0.0.tgz#7bcad469ee7b96e91d12ceb3959c78235a9272e9" 2836 resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.1.0.tgz#bd1442cca1d67dc346a6751559b6d04502103a22"
3112 integrity sha1-e8rUae57lukdEs6zlZx4I1qScuk= 2837 integrity sha512-TxgSKM+7LTA6sidjOiSZK9wxY0ffMPY3Wta//MqwmX0nZuEHc8QrkV8Fh3ZhMJeiH+Uyh/tcaarImRy8u77O7g==
3113 2838
3114fresh@0.3.0: 2839fresh@0.3.0:
3115 version "0.3.0" 2840 version "0.3.0"
@@ -3121,22 +2846,6 @@ fresh@0.5.2:
3121 resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 2846 resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
3122 integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 2847 integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
3123 2848
3124from2@^1.3.0:
3125 version "1.3.0"
3126 resolved "https://registry.yarnpkg.com/from2/-/from2-1.3.0.tgz#88413baaa5f9a597cfde9221d86986cd3c061dfd"
3127 integrity sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=
3128 dependencies:
3129 inherits "~2.0.1"
3130 readable-stream "~1.1.10"
3131
3132from2@^2.1.0:
3133 version "2.3.0"
3134 resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
3135 integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=
3136 dependencies:
3137 inherits "^2.0.1"
3138 readable-stream "^2.0.0"
3139
3140front-matter@2.1.2: 2849front-matter@2.1.2:
3141 version "2.1.2" 2850 version "2.1.2"
3142 resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-2.1.2.tgz#f75983b9f2f413be658c93dfd7bd8ce4078f5cdb" 2851 resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-2.1.2.tgz#f75983b9f2f413be658c93dfd7bd8ce4078f5cdb"
@@ -3175,63 +2884,34 @@ fs-extra@^3.0.1:
3175 jsonfile "^3.0.0" 2884 jsonfile "^3.0.0"
3176 universalify "^0.1.0" 2885 universalify "^0.1.0"
3177 2886
3178fs-extra@^7.0.0: 2887fs-extra@^8.0.1:
3179 version "7.0.1" 2888 version "8.0.1"
3180 resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" 2889 resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.0.1.tgz#90294081f978b1f182f347a440a209154344285b"
3181 integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== 2890 integrity sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A==
3182 dependencies: 2891 dependencies:
3183 graceful-fs "^4.1.2" 2892 graceful-fs "^4.1.2"
3184 jsonfile "^4.0.0" 2893 jsonfile "^4.0.0"
3185 universalify "^0.1.0" 2894 universalify "^0.1.0"
3186 2895
3187fs-minipass@^1.2.5: 2896fs-minipass@^1.2.5:
3188 version "1.2.5" 2897 version "1.2.6"
3189 resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" 2898 resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07"
3190 integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== 2899 integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==
3191 dependencies: 2900 dependencies:
3192 minipass "^2.2.1" 2901 minipass "^2.2.1"
3193 2902
3194fs-vacuum@^1.2.10, fs-vacuum@~1.2.10:
3195 version "1.2.10"
3196 resolved "https://registry.yarnpkg.com/fs-vacuum/-/fs-vacuum-1.2.10.tgz#b7629bec07a4031a2548fdf99f5ecf1cc8b31e36"
3197 integrity sha1-t2Kb7AekAxolSP35n17PHMizHjY=
3198 dependencies:
3199 graceful-fs "^4.1.2"
3200 path-is-inside "^1.0.1"
3201 rimraf "^2.5.2"
3202
3203fs-write-stream-atomic@^1.0.8, fs-write-stream-atomic@~1.0.10:
3204 version "1.0.10"
3205 resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9"
3206 integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=
3207 dependencies:
3208 graceful-fs "^4.1.2"
3209 iferr "^0.1.5"
3210 imurmurhash "^0.1.4"
3211 readable-stream "1 || 2"
3212
3213fs.realpath@^1.0.0: 2903fs.realpath@^1.0.0:
3214 version "1.0.0" 2904 version "1.0.0"
3215 resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 2905 resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
3216 integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 2906 integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
3217 2907
3218fsevents@^1.2.7: 2908fsevents@^1.2.7:
3219 version "1.2.7" 2909 version "1.2.9"
3220 resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" 2910 resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f"
3221 integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== 2911 integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==
3222 dependencies:
3223 nan "^2.9.2"
3224 node-pre-gyp "^0.10.0"
3225
3226fstream@^1.0.0, fstream@^1.0.2:
3227 version "1.0.11"
3228 resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171"
3229 integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=
3230 dependencies: 2912 dependencies:
3231 graceful-fs "^4.1.2" 2913 nan "^2.12.1"
3232 inherits "~2.0.0" 2914 node-pre-gyp "^0.12.0"
3233 mkdirp ">=0.5 0"
3234 rimraf "2"
3235 2915
3236function-bind@^1.1.1: 2916function-bind@^1.1.1:
3237 version "1.1.1" 2917 version "1.1.1"
@@ -3275,25 +2955,6 @@ generate-object-property@^1.1.0:
3275 dependencies: 2955 dependencies:
3276 is-property "^1.0.0" 2956 is-property "^1.0.0"
3277 2957
3278genfun@^5.0.0:
3279 version "5.0.0"
3280 resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537"
3281 integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==
3282
3283gentle-fs@^2.0.0, gentle-fs@^2.0.1:
3284 version "2.0.1"
3285 resolved "https://registry.yarnpkg.com/gentle-fs/-/gentle-fs-2.0.1.tgz#585cfd612bfc5cd52471fdb42537f016a5ce3687"
3286 integrity sha512-cEng5+3fuARewXktTEGbwsktcldA+YsnUEaXZwcK/3pjSE1X9ObnTs+/8rYf8s+RnIcQm2D5x3rwpN7Zom8Bew==
3287 dependencies:
3288 aproba "^1.1.2"
3289 fs-vacuum "^1.2.10"
3290 graceful-fs "^4.1.11"
3291 iferr "^0.1.5"
3292 mkdirp "^0.5.1"
3293 path-is-inside "^1.0.2"
3294 read-cmd-shim "^1.0.1"
3295 slide "^1.1.6"
3296
3297get-browser-rtc@^1.0.0: 2958get-browser-rtc@^1.0.0:
3298 version "1.0.2" 2959 version "1.0.2"
3299 resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz#bbcd40c8451a7ed4ef5c373b8169a409dd1d11d9" 2960 resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz#bbcd40c8451a7ed4ef5c373b8169a409dd1d11d9"
@@ -3304,6 +2965,11 @@ get-caller-file@^1.0.1:
3304 resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" 2965 resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
3305 integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== 2966 integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
3306 2967
2968get-caller-file@^2.0.1:
2969 version "2.0.5"
2970 resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
2971 integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
2972
3307get-func-name@^2.0.0: 2973get-func-name@^2.0.0:
3308 version "2.0.0" 2974 version "2.0.0"
3309 resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 2975 resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
@@ -3314,22 +2980,29 @@ get-own-enumerable-property-symbols@^3.0.0:
3314 resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203" 2980 resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203"
3315 integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg== 2981 integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==
3316 2982
3317get-port@latest: 2983get-port@^5.0.0:
3318 version "4.2.0" 2984 version "5.0.0"
3319 resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" 2985 resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.0.0.tgz#aa22b6b86fd926dd7884de3e23332c9f70c031a6"
3320 integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw== 2986 integrity sha512-imzMU0FjsZqNa6BqOjbbW6w5BivHIuQKopjpPqcnx0AVHJQKCxK1O+Ab3OrVXhrekqfVMjwA9ZYu062R+KcIsQ==
2987 dependencies:
2988 type-fest "^0.3.0"
3321 2989
3322get-stdin@^6.0.0: 2990get-stdin@^6.0.0:
3323 version "6.0.0" 2991 version "6.0.0"
3324 resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" 2992 resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
3325 integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== 2993 integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
3326 2994
2995get-stdin@^7.0.0:
2996 version "7.0.0"
2997 resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6"
2998 integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==
2999
3327get-stream@^3.0.0: 3000get-stream@^3.0.0:
3328 version "3.0.0" 3001 version "3.0.0"
3329 resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" 3002 resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
3330 integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= 3003 integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
3331 3004
3332get-stream@^4.0.0, get-stream@^4.1.0: 3005get-stream@^4.0.0:
3333 version "4.1.0" 3006 version "4.1.0"
3334 resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" 3007 resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
3335 integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== 3008 integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
@@ -3373,7 +3046,7 @@ glob@7.1.2:
3373 once "^1.3.0" 3046 once "^1.3.0"
3374 path-is-absolute "^1.0.0" 3047 path-is-absolute "^1.0.0"
3375 3048
3376glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@~7.1.1: 3049glob@7.1.3:
3377 version "7.1.3" 3050 version "7.1.3"
3378 resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" 3051 resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
3379 integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== 3052 integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
@@ -3385,6 +3058,18 @@ glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@~7.1.1:
3385 once "^1.3.0" 3058 once "^1.3.0"
3386 path-is-absolute "^1.0.0" 3059 path-is-absolute "^1.0.0"
3387 3060
3061glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@~7.1.1:
3062 version "7.1.4"
3063 resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
3064 integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
3065 dependencies:
3066 fs.realpath "^1.0.0"
3067 inflight "^1.0.4"
3068 inherits "2"
3069 minimatch "^3.0.4"
3070 once "^1.3.0"
3071 path-is-absolute "^1.0.0"
3072
3388global-dirs@^0.1.0: 3073global-dirs@^0.1.0:
3389 version "0.1.1" 3074 version "0.1.1"
3390 resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" 3075 resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
@@ -3392,26 +3077,6 @@ global-dirs@^0.1.0:
3392 dependencies: 3077 dependencies:
3393 ini "^1.3.4" 3078 ini "^1.3.4"
3394 3079
3395global-modules@^1.0.0:
3396 version "1.0.0"
3397 resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
3398 integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
3399 dependencies:
3400 global-prefix "^1.0.1"
3401 is-windows "^1.0.1"
3402 resolve-dir "^1.0.0"
3403
3404global-prefix@^1.0.1:
3405 version "1.0.2"
3406 resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
3407 integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
3408 dependencies:
3409 expand-tilde "^2.0.2"
3410 homedir-polyfill "^1.0.1"
3411 ini "^1.3.4"
3412 is-windows "^1.0.1"
3413 which "^1.2.14"
3414
3415globals@^9.2.0: 3080globals@^9.2.0:
3416 version "9.18.0" 3081 version "9.18.0"
3417 resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" 3082 resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
@@ -3461,7 +3126,7 @@ got@^6.7.1:
3461 unzip-response "^2.0.1" 3126 unzip-response "^2.0.1"
3462 url-parse-lax "^1.0.0" 3127 url-parse-lax "^1.0.0"
3463 3128
3464graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: 3129graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
3465 version "4.1.15" 3130 version "4.1.15"
3466 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" 3131 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
3467 integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== 3132 integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
@@ -3530,7 +3195,7 @@ has-symbols@^1.0.0:
3530 resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" 3195 resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
3531 integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= 3196 integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
3532 3197
3533has-unicode@^2.0.0, has-unicode@~2.0.1: 3198has-unicode@^2.0.0:
3534 version "2.0.1" 3199 version "2.0.1"
3535 resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 3200 resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
3536 integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= 3201 integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
@@ -3609,24 +3274,24 @@ helmet-csp@2.7.1:
3609 platform "1.3.5" 3274 platform "1.3.5"
3610 3275
3611helmet@^3.12.1: 3276helmet@^3.12.1:
3612 version "3.16.0" 3277 version "3.18.0"
3613 resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.16.0.tgz#7df41a4bfe4c83d90147c1e30d70893f92a9d97c" 3278 resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.18.0.tgz#37666f7c861bd1ff3015e0cdb903a43501e3da3e"
3614 integrity sha512-rsTKRogc5OYGlvSHuq5QsmOsOzF6uDoMqpfh+Np8r23+QxDq+SUx90Rf8HyIKQVl7H6NswZEwfcykinbAeZ6UQ== 3279 integrity sha512-TsKlGE5UVkV0NiQ4PllV9EVfZklPjyzcMEMjWlyI/8S6epqgRT+4s4GHVgc25x0TixsKvp3L7c91HQQt5l0+QA==
3615 dependencies: 3280 dependencies:
3616 depd "2.0.0" 3281 depd "2.0.0"
3617 dns-prefetch-control "0.1.0" 3282 dns-prefetch-control "0.1.0"
3618 dont-sniff-mimetype "1.0.0" 3283 dont-sniff-mimetype "1.0.0"
3619 expect-ct "0.1.1" 3284 expect-ct "0.2.0"
3620 feature-policy "0.2.0" 3285 feature-policy "0.3.0"
3621 frameguard "3.0.0" 3286 frameguard "3.1.0"
3622 helmet-crossdomain "0.3.0" 3287 helmet-crossdomain "0.3.0"
3623 helmet-csp "2.7.1" 3288 helmet-csp "2.7.1"
3624 hide-powered-by "1.0.0" 3289 hide-powered-by "1.0.0"
3625 hpkp "2.0.0" 3290 hpkp "2.0.0"
3626 hsts "2.2.0" 3291 hsts "2.2.0"
3627 ienoopen "1.1.0" 3292 ienoopen "1.1.0"
3628 nocache "2.0.0" 3293 nocache "2.1.0"
3629 referrer-policy "1.1.0" 3294 referrer-policy "1.2.0"
3630 x-xss-protection "1.1.0" 3295 x-xss-protection "1.1.0"
3631 3296
3632hh-mm-ss@~1.2.0: 3297hh-mm-ss@~1.2.0:
@@ -3641,14 +3306,7 @@ hide-powered-by@1.0.0:
3641 resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b" 3306 resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b"
3642 integrity sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys= 3307 integrity sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys=
3643 3308
3644homedir-polyfill@^1.0.1: 3309hosted-git-info@^2.1.4:
3645 version "1.0.3"
3646 resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
3647 integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
3648 dependencies:
3649 parse-passwd "^1.0.0"
3650
3651hosted-git-info@^2.1.4, hosted-git-info@^2.6.0, hosted-git-info@^2.7.1:
3652 version "2.7.1" 3310 version "2.7.1"
3653 resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" 3311 resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
3654 integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== 3312 integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
@@ -3665,20 +3323,16 @@ hsts@2.2.0:
3665 dependencies: 3323 dependencies:
3666 depd "2.0.0" 3324 depd "2.0.0"
3667 3325
3668http-cache-semantics@^3.8.1: 3326http-errors@1.7.2, http-errors@~1.7.2:
3669 version "3.8.1" 3327 version "1.7.2"
3670 resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" 3328 resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
3671 integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== 3329 integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
3672
3673http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
3674 version "1.6.3"
3675 resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
3676 integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
3677 dependencies: 3330 dependencies:
3678 depd "~1.1.2" 3331 depd "~1.1.2"
3679 inherits "2.0.3" 3332 inherits "2.0.3"
3680 setprototypeof "1.1.0" 3333 setprototypeof "1.1.1"
3681 statuses ">= 1.4.0 < 2" 3334 statuses ">= 1.5.0 < 2"
3335 toidentifier "1.0.0"
3682 3336
3683http-errors@~1.3.1: 3337http-errors@~1.3.1:
3684 version "1.3.1" 3338 version "1.3.1"
@@ -3688,14 +3342,6 @@ http-errors@~1.3.1:
3688 inherits "~2.0.1" 3342 inherits "~2.0.1"
3689 statuses "1" 3343 statuses "1"
3690 3344
3691http-proxy-agent@^2.1.0:
3692 version "2.1.0"
3693 resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
3694 integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==
3695 dependencies:
3696 agent-base "4"
3697 debug "3.1.0"
3698
3699http-signature@^1.2.0, http-signature@~1.2.0: 3345http-signature@^1.2.0, http-signature@~1.2.0:
3700 version "1.2.0" 3346 version "1.2.0"
3701 resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" 3347 resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
@@ -3705,50 +3351,28 @@ http-signature@^1.2.0, http-signature@~1.2.0:
3705 jsprim "^1.2.2" 3351 jsprim "^1.2.2"
3706 sshpk "^1.7.0" 3352 sshpk "^1.7.0"
3707 3353
3708https-proxy-agent@^2.2.1: 3354husky@^2.4.0:
3709 version "2.2.1" 3355 version "2.4.0"
3710 resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" 3356 resolved "https://registry.yarnpkg.com/husky/-/husky-2.4.0.tgz#1bac7c44588f6e91f808b72efc82d24a57194f36"
3711 integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== 3357 integrity sha512-3k1wuZU20gFkphNWMjh2ISCFaqfbaLY7R9FST2Mj9HeRhUK9ydj9qQR8qfXlog3EctVGsyeilcZkIT7uBZDDVA==
3712 dependencies:
3713 agent-base "^4.1.0"
3714 debug "^3.1.0"
3715
3716humanize-ms@^1.2.1:
3717 version "1.2.1"
3718 resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
3719 integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=
3720 dependencies:
3721 ms "^2.0.0"
3722
3723husky@^1.0.0-rc.4:
3724 version "1.3.1"
3725 resolved "https://registry.yarnpkg.com/husky/-/husky-1.3.1.tgz#26823e399300388ca2afff11cfa8a86b0033fae0"
3726 integrity sha512-86U6sVVVf4b5NYSZ0yvv88dRgBSSXXmHaiq5pP4KDj5JVzdwKgBjEtUPOm8hcoytezFwbU+7gotXNhpHdystlg==
3727 dependencies: 3358 dependencies:
3728 cosmiconfig "^5.0.7" 3359 cosmiconfig "^5.2.0"
3729 execa "^1.0.0" 3360 execa "^1.0.0"
3730 find-up "^3.0.0" 3361 find-up "^3.0.0"
3731 get-stdin "^6.0.0" 3362 get-stdin "^7.0.0"
3732 is-ci "^2.0.0" 3363 is-ci "^2.0.0"
3733 pkg-dir "^3.0.0" 3364 pkg-dir "^4.1.0"
3734 please-upgrade-node "^3.1.1" 3365 please-upgrade-node "^3.1.1"
3735 read-pkg "^4.0.1" 3366 read-pkg "^5.1.1"
3736 run-node "^1.0.0" 3367 run-node "^1.0.0"
3737 slash "^2.0.0" 3368 slash "^3.0.0"
3738 3369
3739i@0.3.x: 3370i@0.3.x:
3740 version "0.3.6" 3371 version "0.3.6"
3741 resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" 3372 resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d"
3742 integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0= 3373 integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=
3743 3374
3744iconv-lite@0.4.23: 3375iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
3745 version "0.4.23"
3746 resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
3747 integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==
3748 dependencies:
3749 safer-buffer ">= 2.1.2 < 3"
3750
3751iconv-lite@^0.4.4, iconv-lite@~0.4.13:
3752 version "0.4.24" 3376 version "0.4.24"
3753 resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 3377 resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
3754 integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 3378 integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@@ -3760,16 +3384,6 @@ ienoopen@1.1.0:
3760 resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.1.0.tgz#411e5d530c982287dbdc3bb31e7a9c9e32630974" 3384 resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.1.0.tgz#411e5d530c982287dbdc3bb31e7a9c9e32630974"
3761 integrity sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ== 3385 integrity sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ==
3762 3386
3763iferr@^0.1.5:
3764 version "0.1.5"
3765 resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
3766 integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
3767
3768iferr@^1.0.2:
3769 version "1.0.2"
3770 resolved "https://registry.yarnpkg.com/iferr/-/iferr-1.0.2.tgz#e9fde49a9da06dc4a4194c6c9ed6d08305037a6d"
3771 integrity sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg==
3772
3773ignore-by-default@^1.0.1: 3387ignore-by-default@^1.0.1:
3774 version "1.0.1" 3388 version "1.0.1"
3775 resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" 3389 resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
@@ -3825,7 +3439,7 @@ inflection@1.12.0:
3825 resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" 3439 resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416"
3826 integrity sha1-ogCTVlbW9fa8TcdQLhrstwMihBY= 3440 integrity sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=
3827 3441
3828inflight@^1.0.4, inflight@~1.0.6: 3442inflight@^1.0.4:
3829 version "1.0.6" 3443 version "1.0.6"
3830 resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 3444 resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
3831 integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 3445 integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
@@ -3833,7 +3447,7 @@ inflight@^1.0.4, inflight@~1.0.6:
3833 once "^1.3.0" 3447 once "^1.3.0"
3834 wrappy "1" 3448 wrappy "1"
3835 3449
3836inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: 3450inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
3837 version "2.0.3" 3451 version "2.0.3"
3838 resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 3452 resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
3839 integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 3453 integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
@@ -3843,25 +3457,11 @@ inherits@=2.0.1:
3843 resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" 3457 resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
3844 integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= 3458 integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
3845 3459
3846ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: 3460ini@^1.3.4, ini@~1.3.0:
3847 version "1.3.5" 3461 version "1.3.5"
3848 resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" 3462 resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
3849 integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== 3463 integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
3850 3464
3851init-package-json@^1.10.3:
3852 version "1.10.3"
3853 resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.10.3.tgz#45ffe2f610a8ca134f2bd1db5637b235070f6cbe"
3854 integrity sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==
3855 dependencies:
3856 glob "^7.1.1"
3857 npm-package-arg "^4.0.0 || ^5.0.0 || ^6.0.0"
3858 promzard "^0.3.0"
3859 read "~1.0.1"
3860 read-package-json "1 || 2"
3861 semver "2.x || 3.x || 4 || 5"
3862 validate-npm-package-license "^3.0.1"
3863 validate-npm-package-name "^3.0.0"
3864
3865inquirer@^0.12.0: 3465inquirer@^0.12.0:
3866 version "0.12.0" 3466 version "0.12.0"
3867 resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" 3467 resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
@@ -3881,25 +3481,19 @@ inquirer@^0.12.0:
3881 strip-ansi "^3.0.0" 3481 strip-ansi "^3.0.0"
3882 through "^2.3.6" 3482 through "^2.3.6"
3883 3483
3884invert-kv@^1.0.0:
3885 version "1.0.0"
3886 resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
3887 integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
3888
3889invert-kv@^2.0.0: 3484invert-kv@^2.0.0:
3890 version "2.0.0" 3485 version "2.0.0"
3891 resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" 3486 resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
3892 integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== 3487 integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
3893 3488
3894ioredis@^4.5.1: 3489ioredis@^4.5.1:
3895 version "4.9.0" 3490 version "4.9.5"
3896 resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.9.0.tgz#0c52de498363309ebd48b5f6695d9d432b0f6669" 3491 resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.9.5.tgz#0bbba0a9faae93485d3231e1b819d2d4e23271d9"
3897 integrity sha512-YzfCLsN++Ct43QqGK9CWxaEK6OUvJ7rnENieAPNw3DVp/oF2uBrP2NJChbhO74Ng3LWA+i5zdIEUsZYr6dKDIQ== 3492 integrity sha512-L9MVfvX4F3LScTMEgriCGixzqinJsYy7Mt0NPX8RyuOTmx5JW0744pM4Ze2KVQcP3J0zvKYZ1LywAB6KIq7PYg==
3898 dependencies: 3493 dependencies:
3899 cluster-key-slot "^1.0.6" 3494 cluster-key-slot "^1.0.6"
3900 debug "^3.1.0" 3495 debug "^3.1.0"
3901 denque "^1.1.0" 3496 denque "^1.1.0"
3902 flexbuffer "0.0.6"
3903 lodash.defaults "^4.2.0" 3497 lodash.defaults "^4.2.0"
3904 lodash.flatten "^4.4.0" 3498 lodash.flatten "^4.4.0"
3905 redis-commands "1.4.0" 3499 redis-commands "1.4.0"
@@ -3907,10 +3501,10 @@ ioredis@^4.5.1:
3907 redis-parser "^3.0.0" 3501 redis-parser "^3.0.0"
3908 standard-as-callback "^2.0.1" 3502 standard-as-callback "^2.0.1"
3909 3503
3910ip-anonymize@^0.0.6: 3504ip-anonymize@^0.1.0:
3911 version "0.0.6" 3505 version "0.1.0"
3912 resolved "https://registry.yarnpkg.com/ip-anonymize/-/ip-anonymize-0.0.6.tgz#d2c513e448e874e8cc380d03404691b94b018e68" 3506 resolved "https://registry.yarnpkg.com/ip-anonymize/-/ip-anonymize-0.1.0.tgz#5ead504d01871c5c28189a25382f852036b57f7e"
3913 integrity sha1-0sUT5EjodOjMOA0DQEaRuUsBjmg= 3507 integrity sha512-cZJu+N5JKKFGMK0eEQWNaQMn2EhCysciVM6eotCJwfqotj16BTfVchKsJCH6mQAT9N0GC7oWRcsZ6Lb8dDiwTA==
3914 3508
3915ip-regex@^2.1.0: 3509ip-regex@^2.1.0:
3916 version "2.1.0" 3510 version "2.1.0"
@@ -3918,13 +3512,13 @@ ip-regex@^2.1.0:
3918 integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= 3512 integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
3919 3513
3920ip-set@^1.0.0: 3514ip-set@^1.0.0:
3921 version "1.0.1" 3515 version "1.0.2"
3922 resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.1.tgz#633b66d0bd6c8d0de968d053263c9120d3b6727e" 3516 resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.2.tgz#be4f119f82c124836455993dfcd554639c7007de"
3923 integrity sha1-Yztm0L1sjQ3paNBTJjyRINO2cn4= 3517 integrity sha512-Mb6kv78bTi4RNAIIWL8Bbre7hXOR2pNUi3j8FaQkLaitf/ZWxkq3/iIwXNYk2ACO3IMfdVdQrOkUtwZblO7uBA==
3924 dependencies: 3518 dependencies:
3925 ip "^1.1.3" 3519 ip "^1.1.3"
3926 3520
3927ip@^1.0.1, ip@^1.1.3, ip@^1.1.5: 3521ip@^1.0.1, ip@^1.1.3:
3928 version "1.1.5" 3522 version "1.1.5"
3929 resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" 3523 resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
3930 integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= 3524 integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
@@ -3934,11 +3528,6 @@ ipaddr.js@1.0.5:
3934 resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.0.5.tgz#5fa78cf301b825c78abc3042d812723049ea23c7" 3528 resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.0.5.tgz#5fa78cf301b825c78abc3042d812723049ea23c7"
3935 integrity sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c= 3529 integrity sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c=
3936 3530
3937ipaddr.js@1.8.0:
3938 version "1.8.0"
3939 resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"
3940 integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4=
3941
3942ipaddr.js@1.9.0, "ipaddr.js@>= 0.1.5", ipaddr.js@^1.0.1: 3531ipaddr.js@1.9.0, "ipaddr.js@>= 0.1.5", ipaddr.js@^1.0.1:
3943 version "1.9.0" 3532 version "1.9.0"
3944 resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" 3533 resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
@@ -4135,9 +3724,9 @@ is-my-ip-valid@^1.0.0:
4135 integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ== 3724 integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==
4136 3725
4137is-my-json-valid@^2.10.0: 3726is-my-json-valid@^2.10.0:
4138 version "2.19.0" 3727 version "2.20.0"
4139 resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175" 3728 resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz#1345a6fca3e8daefc10d0fa77067f54cedafd59a"
4140 integrity sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q== 3729 integrity sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==
4141 dependencies: 3730 dependencies:
4142 generate-function "^2.0.0" 3731 generate-function "^2.0.0"
4143 generate-object-property "^1.1.0" 3732 generate-object-property "^1.1.0"
@@ -4256,7 +3845,7 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0:
4256 resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 3845 resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
4257 integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= 3846 integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
4258 3847
4259is-windows@^1.0.1, is-windows@^1.0.2: 3848is-windows@^1.0.2:
4260 version "1.0.2" 3849 version "1.0.2"
4261 resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" 3850 resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
4262 integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== 3851 integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
@@ -4282,9 +3871,9 @@ isexe@^2.0.0:
4282 integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 3871 integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
4283 3872
4284iso-639-3@^1.0.1: 3873iso-639-3@^1.0.1:
4285 version "1.1.0" 3874 version "1.2.0"
4286 resolved "https://registry.yarnpkg.com/iso-639-3/-/iso-639-3-1.1.0.tgz#83722daf55490a707c318ae18a33ba3bab06c843" 3875 resolved "https://registry.yarnpkg.com/iso-639-3/-/iso-639-3-1.2.0.tgz#eee1f5e6ca2bbb33e3ecc910857c1c12e8b295be"
4287 integrity sha512-l3BAnxNpyRIZA4mEzI2md/YVrxQ3hI8hiQe7TFyQknjyOh8vCzobZuAXTFHELco0FBkYRx4FkAlIqkKrHhnzgw== 3876 integrity sha512-jNvD2P4JHNckQH7pc0R0SQ4oPCpyEtgs0nTtjB+DZCUDdygz0cOAxlcnq5KgNjjsqMHbR4Sbgwz2+DflzAZvlQ==
4288 3877
4289isobject@^2.0.0: 3878isobject@^2.0.0:
4290 version "2.1.0" 3879 version "2.1.0"
@@ -4303,23 +3892,15 @@ isstream@0.1.x, isstream@~0.1.2:
4303 resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 3892 resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
4304 integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= 3893 integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
4305 3894
4306js-tokens@^3.0.2: 3895js-tokens@^4.0.0:
4307 version "3.0.2" 3896 version "4.0.0"
4308 resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" 3897 resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
4309 integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= 3898 integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
4310
4311js-yaml@3.12.0:
4312 version "3.12.0"
4313 resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
4314 integrity sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==
4315 dependencies:
4316 argparse "^1.0.7"
4317 esprima "^4.0.0"
4318 3899
4319js-yaml@^3.12.1, js-yaml@^3.13.0, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4: 3900js-yaml@3.13.1, js-yaml@^3.12.1, js-yaml@^3.13.1, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4:
4320 version "3.13.0" 3901 version "3.13.1"
4321 resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.0.tgz#38ee7178ac0eea2c97ff6d96fff4b18c7d8cf98e" 3902 resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
4322 integrity sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ== 3903 integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
4323 dependencies: 3904 dependencies:
4324 argparse "^1.0.7" 3905 argparse "^1.0.7"
4325 esprima "^4.0.0" 3906 esprima "^4.0.0"
@@ -4329,7 +3910,7 @@ jsbn@~0.1.0:
4329 resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 3910 resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
4330 integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= 3911 integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
4331 3912
4332json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: 3913json-parse-better-errors@^1.0.1:
4333 version "1.0.2" 3914 version "1.0.2"
4334 resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" 3915 resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
4335 integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== 3916 integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
@@ -4425,11 +4006,6 @@ jsonld@~1.1.0:
4425 semver "^5.5.0" 4006 semver "^5.5.0"
4426 xmldom "0.1.19" 4007 xmldom "0.1.19"
4427 4008
4428jsonparse@^1.2.0:
4429 version "1.3.1"
4430 resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
4431 integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=
4432
4433jsonpointer.js@0.4.0: 4009jsonpointer.js@0.4.0:
4434 version "0.4.0" 4010 version "0.4.0"
4435 resolved "https://registry.yarnpkg.com/jsonpointer.js/-/jsonpointer.js-0.4.0.tgz#002cb123f767aafdeb0196132ce5c4f9941ccaba" 4011 resolved "https://registry.yarnpkg.com/jsonpointer.js/-/jsonpointer.js-0.4.0.tgz#002cb123f767aafdeb0196132ce5c4f9941ccaba"
@@ -4565,18 +4141,6 @@ latest-version@^3.0.0:
4565 dependencies: 4141 dependencies:
4566 package-json "^4.0.0" 4142 package-json "^4.0.0"
4567 4143
4568lazy-property@~1.0.0:
4569 version "1.0.0"
4570 resolved "https://registry.yarnpkg.com/lazy-property/-/lazy-property-1.0.0.tgz#84ddc4b370679ba8bd4cdcfa4c06b43d57111147"
4571 integrity sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc=
4572
4573lcid@^1.0.0:
4574 version "1.0.0"
4575 resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
4576 integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
4577 dependencies:
4578 invert-kv "^1.0.0"
4579
4580lcid@^2.0.0: 4144lcid@^2.0.0:
4581 version "2.0.0" 4145 version "2.0.0"
4582 resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" 4146 resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
@@ -4592,140 +4156,6 @@ levn@^0.3.0, levn@~0.3.0:
4592 prelude-ls "~1.1.2" 4156 prelude-ls "~1.1.2"
4593 type-check "~0.3.2" 4157 type-check "~0.3.2"
4594 4158
4595libcipm@^3.0.3:
4596 version "3.0.3"
4597 resolved "https://registry.yarnpkg.com/libcipm/-/libcipm-3.0.3.tgz#2e764effe0b90d458790dab3165794c804075ed3"
4598 integrity sha512-71V5CpTI+zFydTc5IjJ/tx8JHbXEJvmYF2zaSVW1V3X1rRnRjXqh44iuiyry1xgi3ProUQ1vX1uwFiWs00+2og==
4599 dependencies:
4600 bin-links "^1.1.2"
4601 bluebird "^3.5.1"
4602 figgy-pudding "^3.5.1"
4603 find-npm-prefix "^1.0.2"
4604 graceful-fs "^4.1.11"
4605 ini "^1.3.5"
4606 lock-verify "^2.0.2"
4607 mkdirp "^0.5.1"
4608 npm-lifecycle "^2.0.3"
4609 npm-logical-tree "^1.2.1"
4610 npm-package-arg "^6.1.0"
4611 pacote "^9.1.0"
4612 read-package-json "^2.0.13"
4613 rimraf "^2.6.2"
4614 worker-farm "^1.6.0"
4615
4616libnpm@^2.0.1:
4617 version "2.0.1"
4618 resolved "https://registry.yarnpkg.com/libnpm/-/libnpm-2.0.1.tgz#a48fcdee3c25e13c77eb7c60a0efe561d7fb0d8f"
4619 integrity sha512-qTKoxyJvpBxHZQB6k0AhSLajyXq9ZE/lUsZzuHAplr2Bpv9G+k4YuYlExYdUCeVRRGqcJt8hvkPh4tBwKoV98w==
4620 dependencies:
4621 bin-links "^1.1.2"
4622 bluebird "^3.5.3"
4623 find-npm-prefix "^1.0.2"
4624 libnpmaccess "^3.0.1"
4625 libnpmconfig "^1.2.1"
4626 libnpmhook "^5.0.2"
4627 libnpmorg "^1.0.0"
4628 libnpmpublish "^1.1.0"
4629 libnpmsearch "^2.0.0"
4630 libnpmteam "^1.0.1"
4631 lock-verify "^2.0.2"
4632 npm-lifecycle "^2.1.0"
4633 npm-logical-tree "^1.2.1"
4634 npm-package-arg "^6.1.0"
4635 npm-profile "^4.0.1"
4636 npm-registry-fetch "^3.8.0"
4637 npmlog "^4.1.2"
4638 pacote "^9.2.3"
4639 read-package-json "^2.0.13"
4640 stringify-package "^1.0.0"
4641
4642libnpmaccess@^3.0.1:
4643 version "3.0.1"
4644 resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-3.0.1.tgz#5b3a9de621f293d425191aa2e779102f84167fa8"
4645 integrity sha512-RlZ7PNarCBt+XbnP7R6PoVgOq9t+kou5rvhaInoNibhPO7eMlRfS0B8yjatgn2yaHIwWNyoJDolC/6Lc5L/IQA==
4646 dependencies:
4647 aproba "^2.0.0"
4648 get-stream "^4.0.0"
4649 npm-package-arg "^6.1.0"
4650 npm-registry-fetch "^3.8.0"
4651
4652libnpmconfig@^1.2.1:
4653 version "1.2.1"
4654 resolved "https://registry.yarnpkg.com/libnpmconfig/-/libnpmconfig-1.2.1.tgz#c0c2f793a74e67d4825e5039e7a02a0044dfcbc0"
4655 integrity sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==
4656 dependencies:
4657 figgy-pudding "^3.5.1"
4658 find-up "^3.0.0"
4659 ini "^1.3.5"
4660
4661libnpmhook@^5.0.2:
4662 version "5.0.2"
4663 resolved "https://registry.yarnpkg.com/libnpmhook/-/libnpmhook-5.0.2.tgz#d12817b0fb893f36f1d5be20017f2aea25825d94"
4664 integrity sha512-vLenmdFWhRfnnZiNFPNMog6CK7Ujofy2TWiM2CrpZUjBRIhHkJeDaAbJdYCT6W4lcHtyrJR8yXW8KFyq6UAp1g==
4665 dependencies:
4666 aproba "^2.0.0"
4667 figgy-pudding "^3.4.1"
4668 get-stream "^4.0.0"
4669 npm-registry-fetch "^3.8.0"
4670
4671libnpmorg@^1.0.0:
4672 version "1.0.0"
4673 resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-1.0.0.tgz#979b868c48ba28c5820e3bb9d9e73c883c16a232"
4674 integrity sha512-o+4eVJBoDGMgRwh2lJY0a8pRV2c/tQM/SxlqXezjcAg26Qe9jigYVs+Xk0vvlYDWCDhP0g74J8UwWeAgsB7gGw==
4675 dependencies:
4676 aproba "^2.0.0"
4677 figgy-pudding "^3.4.1"
4678 get-stream "^4.0.0"
4679 npm-registry-fetch "^3.8.0"
4680
4681libnpmpublish@^1.1.0:
4682 version "1.1.1"
4683 resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-1.1.1.tgz#ff0c6bb0b4ad2bda2ad1f5fba6760a4af37125f0"
4684 integrity sha512-nefbvJd/wY38zdt+b9SHL6171vqBrMtZ56Gsgfd0duEKb/pB8rDT4/ObUQLrHz1tOfht1flt2zM+UGaemzAG5g==
4685 dependencies:
4686 aproba "^2.0.0"
4687 figgy-pudding "^3.5.1"
4688 get-stream "^4.0.0"
4689 lodash.clonedeep "^4.5.0"
4690 normalize-package-data "^2.4.0"
4691 npm-package-arg "^6.1.0"
4692 npm-registry-fetch "^3.8.0"
4693 semver "^5.5.1"
4694 ssri "^6.0.1"
4695
4696libnpmsearch@^2.0.0:
4697 version "2.0.0"
4698 resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-2.0.0.tgz#de05af47ada81554a5f64276a69599070d4a5685"
4699 integrity sha512-vd+JWbTGzOSfiOc+72MU6y7WqmBXn49egCCrIXp27iE/88bX8EpG64ST1blWQI1bSMUr9l1AKPMVsqa2tS5KWA==
4700 dependencies:
4701 figgy-pudding "^3.5.1"
4702 get-stream "^4.0.0"
4703 npm-registry-fetch "^3.8.0"
4704
4705libnpmteam@^1.0.1:
4706 version "1.0.1"
4707 resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-1.0.1.tgz#ff704b1b6c06ea674b3b1101ac3e305f5114f213"
4708 integrity sha512-gDdrflKFCX7TNwOMX1snWojCoDE5LoRWcfOC0C/fqF7mBq8Uz9zWAX4B2RllYETNO7pBupBaSyBDkTAC15cAMg==
4709 dependencies:
4710 aproba "^2.0.0"
4711 figgy-pudding "^3.4.1"
4712 get-stream "^4.0.0"
4713 npm-registry-fetch "^3.8.0"
4714
4715libnpx@^10.2.0:
4716 version "10.2.0"
4717 resolved "https://registry.yarnpkg.com/libnpx/-/libnpx-10.2.0.tgz#1bf4a1c9f36081f64935eb014041da10855e3102"
4718 integrity sha512-X28coei8/XRCt15cYStbLBph+KGhFra4VQhRBPuH/HHMkC5dxM8v24RVgUsvODKCrUZ0eTgiTqJp6zbl0sskQQ==
4719 dependencies:
4720 dotenv "^5.0.1"
4721 npm-package-arg "^6.0.0"
4722 rimraf "^2.6.2"
4723 safe-buffer "^5.1.0"
4724 update-notifier "^2.3.0"
4725 which "^1.3.0"
4726 y18n "^4.0.0"
4727 yargs "^11.0.0"
4728
4729libxmljs@0.19.5: 4159libxmljs@0.19.5:
4730 version "0.19.5" 4160 version "0.19.5"
4731 resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.19.5.tgz#b2f34cc12fd6a3e43670c604c42a902f339ea54d" 4161 resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.19.5.tgz#b2f34cc12fd6a3e43670c604c42a902f339ea54d"
@@ -4736,18 +4166,17 @@ libxmljs@0.19.5:
4736 node-pre-gyp "~0.11.0" 4166 node-pre-gyp "~0.11.0"
4737 4167
4738lint-staged@^8.0.4: 4168lint-staged@^8.0.4:
4739 version "8.1.5" 4169 version "8.2.0"
4740 resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-8.1.5.tgz#372476fe1a58b8834eb562ed4c99126bd60bdd79" 4170 resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-8.2.0.tgz#3d4149a229580815c955047a7acd8f09054be5a9"
4741 integrity sha512-e5ZavfnSLcBJE1BTzRTqw6ly8OkqVyO3GL2M6teSmTBYQ/2BuueD5GIt2RPsP31u/vjKdexUyDCxSyK75q4BDA== 4171 integrity sha512-DxguyxGOIfb67wZ6EOrqzjAbw6ZH9XK3YS74HO+erJf6+SAQeJJPN//GBOG5xhdt2THeuXjVPaHcCYOWGZwRbA==
4742 dependencies: 4172 dependencies:
4743 chalk "^2.3.1" 4173 chalk "^2.3.1"
4744 commander "^2.14.1" 4174 commander "^2.14.1"
4745 cosmiconfig "^5.0.2" 4175 cosmiconfig "^5.2.0"
4746 debug "^3.1.0" 4176 debug "^3.1.0"
4747 dedent "^0.7.0" 4177 dedent "^0.7.0"
4748 del "^3.0.0" 4178 del "^3.0.0"
4749 execa "^1.0.0" 4179 execa "^1.0.0"
4750 find-parent-dir "^0.3.0"
4751 g-status "^2.0.2" 4180 g-status "^2.0.2"
4752 is-glob "^4.0.0" 4181 is-glob "^4.0.0"
4753 is-windows "^1.0.2" 4182 is-windows "^1.0.2"
@@ -4764,7 +4193,7 @@ lint-staged@^8.0.4:
4764 staged-git-files "1.1.2" 4193 staged-git-files "1.1.2"
4765 string-argv "^0.0.2" 4194 string-argv "^0.0.2"
4766 stringify-object "^3.2.2" 4195 stringify-object "^3.2.2"
4767 yup "^0.26.10" 4196 yup "^0.27.0"
4768 4197
4769listr-silent-renderer@^1.1.1: 4198listr-silent-renderer@^1.1.1:
4770 version "1.1.1" 4199 version "1.1.1"
@@ -4821,14 +4250,6 @@ load-ip-set@^2.1.0:
4821 simple-get "^3.0.0" 4250 simple-get "^3.0.0"
4822 split "^1.0.0" 4251 split "^1.0.0"
4823 4252
4824locate-path@^2.0.0:
4825 version "2.0.0"
4826 resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
4827 integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
4828 dependencies:
4829 p-locate "^2.0.0"
4830 path-exists "^3.0.0"
4831
4832locate-path@^3.0.0: 4253locate-path@^3.0.0:
4833 version "3.0.0" 4254 version "3.0.0"
4834 resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 4255 resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
@@ -4837,49 +4258,18 @@ locate-path@^3.0.0:
4837 p-locate "^3.0.0" 4258 p-locate "^3.0.0"
4838 path-exists "^3.0.0" 4259 path-exists "^3.0.0"
4839 4260
4840lock-verify@^2.0.2, lock-verify@^2.1.0: 4261locate-path@^5.0.0:
4841 version "2.1.0" 4262 version "5.0.0"
4842 resolved "https://registry.yarnpkg.com/lock-verify/-/lock-verify-2.1.0.tgz#fff4c918b8db9497af0c5fa7f6d71555de3ceb47" 4263 resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
4843 integrity sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg== 4264 integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
4844 dependencies:
4845 npm-package-arg "^6.1.0"
4846 semver "^5.4.1"
4847
4848lockfile@^1.0.4:
4849 version "1.0.4"
4850 resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609"
4851 integrity sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==
4852 dependencies:
4853 signal-exit "^3.0.2"
4854
4855lodash._baseuniq@~4.6.0:
4856 version "4.6.0"
4857 resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
4858 integrity sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=
4859 dependencies: 4265 dependencies:
4860 lodash._createset "~4.0.0" 4266 p-locate "^4.1.0"
4861 lodash._root "~3.0.0"
4862
4863lodash._createset@~4.0.0:
4864 version "4.0.3"
4865 resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"
4866 integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=
4867
4868lodash._root@~3.0.0:
4869 version "3.0.1"
4870 resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
4871 integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=
4872 4267
4873lodash.capitalize@^4.1.0: 4268lodash.capitalize@^4.1.0:
4874 version "4.2.1" 4269 version "4.2.1"
4875 resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9" 4270 resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9"
4876 integrity sha1-+CbJtOKoUR2E46yinbBeGk87cqk= 4271 integrity sha1-+CbJtOKoUR2E46yinbBeGk87cqk=
4877 4272
4878lodash.clonedeep@^4.5.0, lodash.clonedeep@~4.5.0:
4879 version "4.5.0"
4880 resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
4881 integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
4882
4883lodash.defaults@^4.2.0: 4273lodash.defaults@^4.2.0:
4884 version "4.2.0" 4274 version "4.2.0"
4885 resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" 4275 resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
@@ -4905,21 +4295,6 @@ lodash.kebabcase@^4.0.0:
4905 resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" 4295 resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
4906 integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= 4296 integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY=
4907 4297
4908lodash.union@~4.6.0:
4909 version "4.6.0"
4910 resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
4911 integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
4912
4913lodash.uniq@~4.5.0:
4914 version "4.5.0"
4915 resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
4916 integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
4917
4918lodash.without@~4.4.0:
4919 version "4.4.0"
4920 resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
4921 integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=
4922
4923lodash@4.17.4: 4298lodash@4.17.4:
4924 version "4.17.4" 4299 version "4.17.4"
4925 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" 4300 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
@@ -4974,7 +4349,7 @@ lowercase-keys@^1.0.0:
4974 resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" 4349 resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
4975 integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== 4350 integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
4976 4351
4977lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.1.2, lru-cache@^4.1.3, lru-cache@^4.1.5: 4352lru-cache@4.1.x, lru-cache@^4.0.1:
4978 version "4.1.5" 4353 version "4.1.5"
4979 resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" 4354 resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
4980 integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== 4355 integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
@@ -4982,13 +4357,6 @@ lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.1.2, lru-cache@^4.1.3, lru-cache
4982 pseudomap "^1.0.2" 4357 pseudomap "^1.0.2"
4983 yallist "^2.1.2" 4358 yallist "^2.1.2"
4984 4359
4985lru-cache@^5.1.1:
4986 version "5.1.1"
4987 resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
4988 integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
4989 dependencies:
4990 yallist "^3.0.2"
4991
4992lru-queue@0.1: 4360lru-queue@0.1:
4993 version "0.1.0" 4361 version "0.1.0"
4994 resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" 4362 resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3"
@@ -5049,23 +4417,6 @@ make-error@^1.1.1:
5049 resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" 4417 resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8"
5050 integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== 4418 integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==
5051 4419
5052make-fetch-happen@^4.0.1:
5053 version "4.0.1"
5054 resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-4.0.1.tgz#141497cb878f243ba93136c83d8aba12c216c083"
5055 integrity sha512-7R5ivfy9ilRJ1EMKIOziwrns9fGeAD4bAha8EB7BIiBBLHm2KeTUGCrICFt2rbHfzheTLynv50GnNTK1zDTrcQ==
5056 dependencies:
5057 agentkeepalive "^3.4.1"
5058 cacache "^11.0.1"
5059 http-cache-semantics "^3.8.1"
5060 http-proxy-agent "^2.1.0"
5061 https-proxy-agent "^2.2.1"
5062 lru-cache "^4.1.2"
5063 mississippi "^3.0.0"
5064 node-fetch-npm "^2.0.2"
5065 promise-retry "^1.1.1"
5066 socks-proxy-agent "^4.0.0"
5067 ssri "^6.0.0"
5068
5069map-age-cleaner@^0.1.1: 4420map-age-cleaner@^0.1.1:
5070 version "0.1.3" 4421 version "0.1.3"
5071 resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" 4422 resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
@@ -5085,10 +4436,10 @@ map-visit@^1.0.0:
5085 dependencies: 4436 dependencies:
5086 object-visit "^1.0.0" 4437 object-visit "^1.0.0"
5087 4438
5088marked-man@^0.4.2: 4439marked-man@^0.6.0:
5089 version "0.4.2" 4440 version "0.6.0"
5090 resolved "https://registry.yarnpkg.com/marked-man/-/marked-man-0.4.2.tgz#4507ee0bafa04f46f9b48082f62b3593c8d667bb" 4441 resolved "https://registry.yarnpkg.com/marked-man/-/marked-man-0.6.0.tgz#ac049f840cf633a0f679af58f321c7de3dd583d8"
5091 integrity sha512-4AMgee2zyjzgybboMBjAfDQ1ZUnBFDmxTKld7xuEc9N5tY3T7CqQYqYfKAkUc73tNLeOdwKcR3N5p1toXLiHAA== 4442 integrity sha512-lqzGe2uPo0KPO5J5yyfZ6PbEpZS6VIMHIzltXNzdwTNBysD0pNLtTaGrtT5R4aFT8UaVR3Fuz9rN3SEFYnea5Q==
5092 4443
5093matcher@^1.0.0: 4444matcher@^1.0.0:
5094 version "1.1.1" 4445 version "1.1.1"
@@ -5106,11 +4457,6 @@ md5@^2.2.1:
5106 crypt "~0.0.1" 4457 crypt "~0.0.1"
5107 is-buffer "~1.1.1" 4458 is-buffer "~1.1.1"
5108 4459
5109meant@~1.0.1:
5110 version "1.0.1"
5111 resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.1.tgz#66044fea2f23230ec806fb515efea29c44d2115d"
5112 integrity sha512-UakVLFjKkbbUwNWJ2frVLnnAtbb7D7DsloxRd3s/gDpI8rdv8W5Hp3NaDb+POBI1fQdeussER6NB8vpcRURvlg==
5113
5114media-typer@0.3.0: 4460media-typer@0.3.0:
5115 version "0.3.0" 4461 version "0.3.0"
5116 resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 4462 resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@@ -5125,13 +4471,6 @@ mediasource@^2.1.0, mediasource@^2.2.2:
5125 readable-stream "^3.0.0" 4471 readable-stream "^3.0.0"
5126 to-arraybuffer "^1.0.1" 4472 to-arraybuffer "^1.0.1"
5127 4473
5128mem@^1.1.0:
5129 version "1.1.0"
5130 resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76"
5131 integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=
5132 dependencies:
5133 mimic-fn "^1.0.0"
5134
5135mem@^4.0.0: 4474mem@^4.0.0:
5136 version "4.3.0" 4475 version "4.3.0"
5137 resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" 4476 resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
@@ -5175,7 +4514,7 @@ methods@^1.1.1, methods@^1.1.2, methods@~1.1.2:
5175 resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 4514 resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
5176 integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 4515 integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
5177 4516
5178micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: 4517micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
5179 version "3.1.10" 4518 version "3.1.10"
5180 resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" 4519 resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
5181 integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== 4520 integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
@@ -5194,37 +4533,32 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
5194 snapdragon "^0.8.1" 4533 snapdragon "^0.8.1"
5195 to-regex "^3.0.2" 4534 to-regex "^3.0.2"
5196 4535
5197mime-db@~1.38.0: 4536mime-db@1.40.0:
5198 version "1.38.0" 4537 version "1.40.0"
5199 resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" 4538 resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
5200 integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg== 4539 integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
5201 4540
5202mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.18, mime-types@~2.1.19, mime-types@~2.1.6: 4541mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.6:
5203 version "2.1.22" 4542 version "2.1.24"
5204 resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd" 4543 resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
5205 integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog== 4544 integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
5206 dependencies: 4545 dependencies:
5207 mime-db "~1.38.0" 4546 mime-db "1.40.0"
5208 4547
5209mime@1.3.4: 4548mime@1.3.4:
5210 version "1.3.4" 4549 version "1.3.4"
5211 resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" 4550 resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
5212 integrity sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM= 4551 integrity sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=
5213 4552
5214mime@1.4.1: 4553mime@1.6.0, mime@^1.3.4, mime@^1.4.1:
5215 version "1.4.1"
5216 resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
5217 integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
5218
5219mime@^1.3.4, mime@^1.4.1:
5220 version "1.6.0" 4554 version "1.6.0"
5221 resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 4555 resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
5222 integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 4556 integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
5223 4557
5224mime@^2.4.0: 4558mime@^2.4.0:
5225 version "2.4.0" 4559 version "2.4.3"
5226 resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.0.tgz#e051fd881358585f3279df333fe694da0bcffdd6" 4560 resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe"
5227 integrity sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w== 4561 integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==
5228 4562
5229mimelib@^0.3.0: 4563mimelib@^0.3.0:
5230 version "0.3.1" 4564 version "0.3.1"
@@ -5276,7 +4610,7 @@ minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0:
5276 resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 4610 resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
5277 integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= 4611 integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
5278 4612
5279minipass@^2.2.1, minipass@^2.3.4, minipass@^2.3.5: 4613minipass@^2.2.1, minipass@^2.3.5:
5280 version "2.3.5" 4614 version "2.3.5"
5281 resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" 4615 resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
5282 integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== 4616 integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
@@ -5284,29 +4618,13 @@ minipass@^2.2.1, minipass@^2.3.4, minipass@^2.3.5:
5284 safe-buffer "^5.1.2" 4618 safe-buffer "^5.1.2"
5285 yallist "^3.0.0" 4619 yallist "^3.0.0"
5286 4620
5287minizlib@^1.1.1: 4621minizlib@^1.2.1:
5288 version "1.2.1" 4622 version "1.2.1"
5289 resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" 4623 resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
5290 integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== 4624 integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
5291 dependencies: 4625 dependencies:
5292 minipass "^2.2.1" 4626 minipass "^2.2.1"
5293 4627
5294mississippi@^3.0.0:
5295 version "3.0.0"
5296 resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022"
5297 integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==
5298 dependencies:
5299 concat-stream "^1.5.0"
5300 duplexify "^3.4.2"
5301 end-of-stream "^1.1.0"
5302 flush-write-stream "^1.0.0"
5303 from2 "^2.1.0"
5304 parallel-transform "^1.1.0"
5305 pump "^3.0.0"
5306 pumpify "^1.3.3"
5307 stream-each "^1.1.0"
5308 through2 "^2.0.0"
5309
5310mixin-deep@^1.2.0: 4628mixin-deep@^1.2.0:
5311 version "1.3.1" 4629 version "1.3.1"
5312 resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" 4630 resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
@@ -5315,46 +4633,56 @@ mixin-deep@^1.2.0:
5315 for-in "^1.0.2" 4633 for-in "^1.0.2"
5316 is-extendable "^1.0.1" 4634 is-extendable "^1.0.1"
5317 4635
5318mkdirp@0.5.1, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: 4636mkdirp@0.5.1, mkdirp@0.x.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
5319 version "0.5.1" 4637 version "0.5.1"
5320 resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 4638 resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
5321 integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 4639 integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
5322 dependencies: 4640 dependencies:
5323 minimist "0.0.8" 4641 minimist "0.0.8"
5324 4642
4643mocha-parallel-tests@^2.1.0:
4644 version "2.1.2"
4645 resolved "https://registry.yarnpkg.com/mocha-parallel-tests/-/mocha-parallel-tests-2.1.2.tgz#2f5c24022257e5fc6c63a6bd22d49c1487496b26"
4646 integrity sha512-FatFg3MHLio9ir1oP6J0HNEo6R5344JC1y+We90iALdiT9F9xNPN0KbGXxRNlGlSl0GodfSESKbRzBvT9ctgIw==
4647 dependencies:
4648 circular-json "^0.5.9"
4649 debug "^4.1.1"
4650 uuid "^3.3.2"
4651 yargs "^13.2.2"
4652
5325mocha@^6.0.0: 4653mocha@^6.0.0:
5326 version "6.0.2" 4654 version "6.1.4"
5327 resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.0.2.tgz#cdc1a6fdf66472c079b5605bac59d29807702d2c" 4655 resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.1.4.tgz#e35fada242d5434a7e163d555c705f6875951640"
5328 integrity sha512-RtTJsmmToGyeTznSOMoM6TPEk1A84FQaHIciKrRqARZx+B5ccJ5tXlmJzEKGBxZdqk9UjpRsesZTUkZmR5YnuQ== 4656 integrity sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg==
5329 dependencies: 4657 dependencies:
5330 ansi-colors "3.2.3" 4658 ansi-colors "3.2.3"
5331 browser-stdout "1.3.1" 4659 browser-stdout "1.3.1"
5332 debug "3.2.6" 4660 debug "3.2.6"
5333 diff "3.5.0" 4661 diff "3.5.0"
5334 escape-string-regexp "1.0.5" 4662 escape-string-regexp "1.0.5"
5335 findup-sync "2.0.0" 4663 find-up "3.0.0"
5336 glob "7.1.3" 4664 glob "7.1.3"
5337 growl "1.10.5" 4665 growl "1.10.5"
5338 he "1.2.0" 4666 he "1.2.0"
5339 js-yaml "3.12.0" 4667 js-yaml "3.13.1"
5340 log-symbols "2.2.0" 4668 log-symbols "2.2.0"
5341 minimatch "3.0.4" 4669 minimatch "3.0.4"
5342 mkdirp "0.5.1" 4670 mkdirp "0.5.1"
5343 ms "2.1.1" 4671 ms "2.1.1"
5344 node-environment-flags "1.0.4" 4672 node-environment-flags "1.0.5"
5345 object.assign "4.1.0" 4673 object.assign "4.1.0"
5346 strip-json-comments "2.0.1" 4674 strip-json-comments "2.0.1"
5347 supports-color "6.0.0" 4675 supports-color "6.0.0"
5348 which "1.3.1" 4676 which "1.3.1"
5349 wide-align "1.1.3" 4677 wide-align "1.1.3"
5350 yargs "12.0.5" 4678 yargs "13.2.2"
5351 yargs-parser "11.1.1" 4679 yargs-parser "13.0.0"
5352 yargs-unparser "1.5.0" 4680 yargs-unparser "1.5.0"
5353 4681
5354moment-timezone@^0.5.21, moment-timezone@^0.5.23: 4682moment-timezone@^0.5.21, moment-timezone@^0.5.23:
5355 version "0.5.23" 4683 version "0.5.25"
5356 resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.23.tgz#7cbb00db2c14c71b19303cb47b0fb0a6d8651463" 4684 resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.25.tgz#a11bfa2f74e088327f2cd4c08b3e7bdf55957810"
5357 integrity sha512-WHFH85DkCfiNMDX5D3X7hpNH3/PUhjTGcD0U1SgfBGZxJ3qUmJh5FdvaFjcClxOvB3rzdfj4oRffbI38jEnC1w== 4685 integrity sha512-DgEaTyN/z0HFaVcVbSyVCUU6HeFdnNC3vE4c9cgu2dgMTvjBUBdBzWfasTBmAW45u5OIMeCJtU8yNjM22DHucw==
5358 dependencies: 4686 dependencies:
5359 moment ">= 2.9.0" 4687 moment ">= 2.9.0"
5360 4688
@@ -5374,18 +4702,6 @@ morgan@^1.5.3:
5374 on-finished "~2.3.0" 4702 on-finished "~2.3.0"
5375 on-headers "~1.0.1" 4703 on-headers "~1.0.1"
5376 4704
5377move-concurrently@^1.0.1:
5378 version "1.0.1"
5379 resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
5380 integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=
5381 dependencies:
5382 aproba "^1.1.1"
5383 copy-concurrently "^1.0.0"
5384 fs-write-stream-atomic "^1.0.8"
5385 mkdirp "^0.5.1"
5386 rimraf "^2.5.4"
5387 run-queue "^1.0.3"
5388
5389mp4-box-encoding@^1.1.0, mp4-box-encoding@^1.3.0: 4705mp4-box-encoding@^1.1.0, mp4-box-encoding@^1.3.0:
5390 version "1.3.0" 4706 version "1.3.0"
5391 resolved "https://registry.yarnpkg.com/mp4-box-encoding/-/mp4-box-encoding-1.3.0.tgz#2a6f750947ff68c3a498fd76cd6424c53d995d48" 4707 resolved "https://registry.yarnpkg.com/mp4-box-encoding/-/mp4-box-encoding-1.3.0.tgz#2a6f750947ff68c3a498fd76cd6424c53d995d48"
@@ -5421,7 +4737,7 @@ ms@2.0.0:
5421 resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 4737 resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
5422 integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 4738 integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
5423 4739
5424ms@2.1.1, ms@^2.0.0, ms@^2.1.1: 4740ms@2.1.1, ms@^2.1.1:
5425 version "2.1.1" 4741 version "2.1.1"
5426 resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 4742 resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
5427 integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 4743 integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
@@ -5458,16 +4774,16 @@ mute-stream@~0.0.4:
5458 resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" 4774 resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
5459 integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== 4775 integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
5460 4776
5461nan@2.13.1: 4777nan@2.13.2:
5462 version "2.13.1"
5463 resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.1.tgz#a15bee3790bde247e8f38f1d446edcdaeb05f2dd"
5464 integrity sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA==
5465
5466nan@^2.10.0, nan@^2.13.1, nan@^2.9.2:
5467 version "2.13.2" 4778 version "2.13.2"
5468 resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" 4779 resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
5469 integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw== 4780 integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==
5470 4781
4782nan@^2.10.0, nan@^2.12.1, nan@^2.13.2:
4783 version "2.14.0"
4784 resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
4785 integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
4786
5471nan@~2.10.0: 4787nan@~2.10.0:
5472 version "2.10.0" 4788 version "2.10.0"
5473 resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" 4789 resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
@@ -5501,11 +4817,11 @@ ncp@1.0.x:
5501 integrity sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY= 4817 integrity sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY=
5502 4818
5503needle@^2.2.1: 4819needle@^2.2.1:
5504 version "2.2.4" 4820 version "2.4.0"
5505 resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" 4821 resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
5506 integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== 4822 integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==
5507 dependencies: 4823 dependencies:
5508 debug "^2.1.2" 4824 debug "^3.2.6"
5509 iconv-lite "^0.4.4" 4825 iconv-lite "^0.4.4"
5510 sax "^1.2.4" 4826 sax "^1.2.4"
5511 4827
@@ -5519,6 +4835,11 @@ negotiator@0.6.1:
5519 resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" 4835 resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
5520 integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= 4836 integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=
5521 4837
4838negotiator@0.6.2:
4839 version "0.6.2"
4840 resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
4841 integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
4842
5522netmask@^1.0.6: 4843netmask@^1.0.6:
5523 version "1.0.6" 4844 version "1.0.6"
5524 resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" 4845 resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35"
@@ -5547,38 +4868,25 @@ nice-try@^1.0.4:
5547 resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" 4868 resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
5548 integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== 4869 integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
5549 4870
5550nocache@2.0.0: 4871nocache@2.1.0:
5551 version "2.0.0" 4872 version "2.1.0"
5552 resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.0.0.tgz#202b48021a0c4cbde2df80de15a17443c8b43980" 4873 resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f"
5553 integrity sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA= 4874 integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==
5554 4875
5555node-abi@^2.7.0: 4876node-abi@^2.7.0:
5556 version "2.7.1" 4877 version "2.8.0"
5557 resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.7.1.tgz#a8997ae91176a5fbaa455b194976e32683cda643" 4878 resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.8.0.tgz#bd2e88dbe6a6871e6dd08553e0605779325737ec"
5558 integrity sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw== 4879 integrity sha512-1/aa2clS0pue0HjckL62CsbhWWU35HARvBDXcJtYKbYR7LnIutmpxmXbuDMV9kEviD2lP/wACOgWmmwljghHyQ==
5559 dependencies: 4880 dependencies:
5560 semver "^5.4.1" 4881 semver "^5.4.1"
5561 4882
5562node-addon-api@^1.6.0: 4883node-environment-flags@1.0.5:
5563 version "1.6.2" 4884 version "1.0.5"
5564 resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.2.tgz#d8aad9781a5cfc4132cc2fecdbdd982534265217" 4885 resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a"
5565 integrity sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA== 4886 integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==
5566
5567node-environment-flags@1.0.4:
5568 version "1.0.4"
5569 resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.4.tgz#0b784a6551426bfc16d3b2208424dcbc2b2ff038"
5570 integrity sha512-M9rwCnWVLW7PX+NUWe3ejEdiLYinRpsEre9hMkU/6NS4h+EEulYaDH1gCEZ2gyXsmw+RXYDaV2JkkTNcsPDJ0Q==
5571 dependencies: 4887 dependencies:
5572 object.getownpropertydescriptors "^2.0.3" 4888 object.getownpropertydescriptors "^2.0.3"
5573 4889 semver "^5.7.0"
5574node-fetch-npm@^2.0.2:
5575 version "2.0.2"
5576 resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7"
5577 integrity sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==
5578 dependencies:
5579 encoding "^0.1.11"
5580 json-parse-better-errors "^1.0.0"
5581 safe-buffer "^5.1.1"
5582 4890
5583node-forge@^0.7.1: 4891node-forge@^0.7.1:
5584 version "0.7.6" 4892 version "0.7.6"
@@ -5590,25 +4898,7 @@ node-gyp-build@~3.7.0:
5590 resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d" 4898 resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d"
5591 integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w== 4899 integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w==
5592 4900
5593node-gyp@^3.8.0: 4901node-pre-gyp@0.12.0, node-pre-gyp@^0.12.0:
5594 version "3.8.0"
5595 resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
5596 integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==
5597 dependencies:
5598 fstream "^1.0.0"
5599 glob "^7.0.3"
5600 graceful-fs "^4.1.2"
5601 mkdirp "^0.5.0"
5602 nopt "2 || 3"
5603 npmlog "0 || 1 || 2 || 3 || 4"
5604 osenv "0"
5605 request "^2.87.0"
5606 rimraf "2"
5607 semver "~5.3.0"
5608 tar "^2.0.0"
5609 which "1"
5610
5611node-pre-gyp@0.12.0:
5612 version "0.12.0" 4902 version "0.12.0"
5613 resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" 4903 resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149"
5614 integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== 4904 integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==
@@ -5624,22 +4914,6 @@ node-pre-gyp@0.12.0:
5624 semver "^5.3.0" 4914 semver "^5.3.0"
5625 tar "^4" 4915 tar "^4"
5626 4916
5627node-pre-gyp@^0.10.0:
5628 version "0.10.3"
5629 resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc"
5630 integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==
5631 dependencies:
5632 detect-libc "^1.0.2"
5633 mkdirp "^0.5.1"
5634 needle "^2.2.1"
5635 nopt "^4.0.1"
5636 npm-packlist "^1.1.6"
5637 npmlog "^4.0.2"
5638 rc "^1.2.7"
5639 rimraf "^2.6.1"
5640 semver "^5.3.0"
5641 tar "^4"
5642
5643node-pre-gyp@~0.11.0: 4917node-pre-gyp@~0.11.0:
5644 version "0.11.0" 4918 version "0.11.0"
5645 resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" 4919 resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054"
@@ -5681,16 +4955,16 @@ nodemailer-shared@^1.1.0:
5681 nodemailer-fetch "1.6.0" 4955 nodemailer-fetch "1.6.0"
5682 4956
5683nodemailer@^6.0.0: 4957nodemailer@^6.0.0:
5684 version "6.0.0" 4958 version "6.2.1"
5685 resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.0.0.tgz#d9761128771739dc87c1fdd747f569b7f135cb02" 4959 resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.2.1.tgz#20d773925eb8f7a06166a0b62c751dc8290429f3"
5686 integrity sha512-PMQJyLhoNAMoBU1hEh5aaUkpa/tcDNwzS7s7zow/myKfoEoZewMxUuWZqQ5yjYsAnvE484KSkYH5s6iPvcjhCg== 4960 integrity sha512-TagB7iuIi9uyNgHExo8lUDq3VK5/B0BpbkcjIgNvxbtVrjNqq0DwAOTuzALPVkK76kMhTSzIgHqg8X1uklVs6g==
5687 4961
5688nodemon@^1.18.6: 4962nodemon@^1.18.6:
5689 version "1.18.10" 4963 version "1.19.1"
5690 resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.10.tgz#3ba63f64eb4c283cf3e4f75f30817e9d4f393afe" 4964 resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.19.1.tgz#576f0aad0f863aabf8c48517f6192ff987cd5071"
5691 integrity sha512-we51yBb1TfEvZamFchRgcfLbVYgg0xlGbyXmOtbBzDwxwgewYS/YbZ5tnlnsH51+AoSTTsT3A2E/FloUbtH8cQ== 4965 integrity sha512-/DXLzd/GhiaDXXbGId5BzxP1GlsqtMGM9zTmkWrgXtSqjKmGSbLicM/oAy4FR0YWm14jCHRwnR31AHS2dYFHrg==
5692 dependencies: 4966 dependencies:
5693 chokidar "^2.1.0" 4967 chokidar "^2.1.5"
5694 debug "^3.1.0" 4968 debug "^3.1.0"
5695 ignore-by-default "^1.0.1" 4969 ignore-by-default "^1.0.1"
5696 minimatch "^3.0.4" 4970 minimatch "^3.0.4"
@@ -5706,14 +4980,7 @@ noop-logger@^0.1.1:
5706 resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" 4980 resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2"
5707 integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= 4981 integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=
5708 4982
5709"nopt@2 || 3": 4983nopt@^4.0.1:
5710 version "3.0.6"
5711 resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
5712 integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
5713 dependencies:
5714 abbrev "1"
5715
5716nopt@^4.0.1, nopt@~4.0.1:
5717 version "4.0.1" 4984 version "4.0.1"
5718 resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" 4985 resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
5719 integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= 4986 integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
@@ -5728,7 +4995,7 @@ nopt@~1.0.10:
5728 dependencies: 4995 dependencies:
5729 abbrev "1" 4996 abbrev "1"
5730 4997
5731normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.4.0, normalize-package-data@^2.5.0: 4998normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
5732 version "2.5.0" 4999 version "2.5.0"
5733 resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" 5000 resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
5734 integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== 5001 integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
@@ -5750,61 +5017,12 @@ normalize-path@^3.0.0:
5750 resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 5017 resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
5751 integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 5018 integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
5752 5019
5753npm-audit-report@^1.3.2:
5754 version "1.3.2"
5755 resolved "https://registry.yarnpkg.com/npm-audit-report/-/npm-audit-report-1.3.2.tgz#303bc78cd9e4c226415076a4f7e528c89fc77018"
5756 integrity sha512-abeqS5ONyXNaZJPGAf6TOUMNdSe1Y6cpc9MLBRn+CuUoYbfdca6AxOyXVlfIv9OgKX+cacblbG5w7A6ccwoTPw==
5757 dependencies:
5758 cli-table3 "^0.5.0"
5759 console-control-strings "^1.1.0"
5760
5761npm-bundled@^1.0.1: 5020npm-bundled@^1.0.1:
5762 version "1.0.6" 5021 version "1.0.6"
5763 resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" 5022 resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd"
5764 integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== 5023 integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
5765 5024
5766npm-cache-filename@~1.0.2: 5025npm-packlist@^1.1.6:
5767 version "1.0.2"
5768 resolved "https://registry.yarnpkg.com/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz#ded306c5b0bfc870a9e9faf823bc5f283e05ae11"
5769 integrity sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=
5770
5771npm-install-checks@~3.0.0:
5772 version "3.0.0"
5773 resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-3.0.0.tgz#d4aecdfd51a53e3723b7b2f93b2ee28e307bc0d7"
5774 integrity sha1-1K7N/VGlPjcjt7L5Oy7ijjB7wNc=
5775 dependencies:
5776 semver "^2.3.0 || 3.x || 4 || 5"
5777
5778npm-lifecycle@^2.0.3, npm-lifecycle@^2.1.0:
5779 version "2.1.0"
5780 resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-2.1.0.tgz#1eda2eedb82db929e3a0c50341ab0aad140ed569"
5781 integrity sha512-QbBfLlGBKsktwBZLj6AviHC6Q9Y3R/AY4a2PYSIRhSKSS0/CxRyD/PfxEX6tPeOCXQgMSNdwGeECacstgptc+g==
5782 dependencies:
5783 byline "^5.0.0"
5784 graceful-fs "^4.1.11"
5785 node-gyp "^3.8.0"
5786 resolve-from "^4.0.0"
5787 slide "^1.1.6"
5788 uid-number "0.0.6"
5789 umask "^1.1.0"
5790 which "^1.3.1"
5791
5792npm-logical-tree@^1.2.1:
5793 version "1.2.1"
5794 resolved "https://registry.yarnpkg.com/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz#44610141ca24664cad35d1e607176193fd8f5b88"
5795 integrity sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg==
5796
5797"npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", npm-package-arg@^6.0.0, npm-package-arg@^6.1.0:
5798 version "6.1.0"
5799 resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1"
5800 integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA==
5801 dependencies:
5802 hosted-git-info "^2.6.0"
5803 osenv "^0.1.5"
5804 semver "^5.5.0"
5805 validate-npm-package-name "^3.0.0"
5806
5807npm-packlist@^1.1.12, npm-packlist@^1.1.6, npm-packlist@^1.4.1:
5808 version "1.4.1" 5026 version "1.4.1"
5809 resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" 5027 resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc"
5810 integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw== 5028 integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==
@@ -5819,36 +5037,6 @@ npm-path@^2.0.2:
5819 dependencies: 5037 dependencies:
5820 which "^1.2.10" 5038 which "^1.2.10"
5821 5039
5822npm-pick-manifest@^2.2.3:
5823 version "2.2.3"
5824 resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz#32111d2a9562638bb2c8f2bf27f7f3092c8fae40"
5825 integrity sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA==
5826 dependencies:
5827 figgy-pudding "^3.5.1"
5828 npm-package-arg "^6.0.0"
5829 semver "^5.4.1"
5830
5831npm-profile@^4.0.1:
5832 version "4.0.1"
5833 resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-4.0.1.tgz#d350f7a5e6b60691c7168fbb8392c3603583f5aa"
5834 integrity sha512-NQ1I/1Q7YRtHZXkcuU1/IyHeLy6pd+ScKg4+DQHdfsm769TGq6HPrkbuNJVJS4zwE+0mvvmeULzQdWn2L2EsVA==
5835 dependencies:
5836 aproba "^1.1.2 || 2"
5837 figgy-pudding "^3.4.1"
5838 npm-registry-fetch "^3.8.0"
5839
5840npm-registry-fetch@^3.8.0, npm-registry-fetch@^3.9.0:
5841 version "3.9.0"
5842 resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-3.9.0.tgz#44d841780e2833f06accb34488f8c7450d1a6856"
5843 integrity sha512-srwmt8YhNajAoSAaDWndmZgx89lJwIZ1GWxOuckH4Coek4uHv5S+o/l9FLQe/awA+JwTnj4FJHldxhlXdZEBmw==
5844 dependencies:
5845 JSONStream "^1.3.4"
5846 bluebird "^3.5.1"
5847 figgy-pudding "^3.4.1"
5848 lru-cache "^4.1.3"
5849 make-fetch-happen "^4.0.1"
5850 npm-package-arg "^6.1.0"
5851
5852npm-run-path@^2.0.0: 5040npm-run-path@^2.0.0:
5853 version "2.0.2" 5041 version "2.0.2"
5854 resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" 5042 resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
@@ -5856,11 +5044,6 @@ npm-run-path@^2.0.0:
5856 dependencies: 5044 dependencies:
5857 path-key "^2.0.0" 5045 path-key "^2.0.0"
5858 5046
5859npm-user-validate@~1.0.0:
5860 version "1.0.0"
5861 resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-1.0.0.tgz#8ceca0f5cea04d4e93519ef72d0557a75122e951"
5862 integrity sha1-jOyg9c6gTU6TUZ73LQVXp1Ei6VE=
5863
5864npm-which@^3.0.1: 5047npm-which@^3.0.1:
5865 version "3.0.1" 5048 version "3.0.1"
5866 resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa" 5049 resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa"
@@ -5870,121 +5053,7 @@ npm-which@^3.0.1:
5870 npm-path "^2.0.2" 5053 npm-path "^2.0.2"
5871 which "^1.2.10" 5054 which "^1.2.10"
5872 5055
5873npm@*: 5056npmlog@^4.0.1, npmlog@^4.0.2, npmlog@^4.1.2:
5874 version "6.9.0"
5875 resolved "https://registry.yarnpkg.com/npm/-/npm-6.9.0.tgz#5296720486814a64a7fb082de00c4b5cfd11211f"
5876 integrity sha512-91V+zB5hDxO+Jyp2sUKS7juHlIM95dGQxTeQtmZI1nAI/7kjWXFipPrtwwKjhyKmV4GsS2LzJhrxRjGWsU9z/w==
5877 dependencies:
5878 JSONStream "^1.3.5"
5879 abbrev "~1.1.1"
5880 ansicolors "~0.3.2"
5881 ansistyles "~0.1.3"
5882 aproba "^2.0.0"
5883 archy "~1.0.0"
5884 bin-links "^1.1.2"
5885 bluebird "^3.5.3"
5886 byte-size "^5.0.1"
5887 cacache "^11.3.2"
5888 call-limit "~1.1.0"
5889 chownr "^1.1.1"
5890 ci-info "^2.0.0"
5891 cli-columns "^3.1.2"
5892 cli-table3 "^0.5.1"
5893 cmd-shim "~2.0.2"
5894 columnify "~1.5.4"
5895 config-chain "^1.1.12"
5896 detect-indent "~5.0.0"
5897 detect-newline "^2.1.0"
5898 dezalgo "~1.0.3"
5899 editor "~1.0.0"
5900 figgy-pudding "^3.5.1"
5901 find-npm-prefix "^1.0.2"
5902 fs-vacuum "~1.2.10"
5903 fs-write-stream-atomic "~1.0.10"
5904 gentle-fs "^2.0.1"
5905 glob "^7.1.3"
5906 graceful-fs "^4.1.15"
5907 has-unicode "~2.0.1"
5908 hosted-git-info "^2.7.1"
5909 iferr "^1.0.2"
5910 inflight "~1.0.6"
5911 inherits "~2.0.3"
5912 ini "^1.3.5"
5913 init-package-json "^1.10.3"
5914 is-cidr "^3.0.0"
5915 json-parse-better-errors "^1.0.2"
5916 lazy-property "~1.0.0"
5917 libcipm "^3.0.3"
5918 libnpm "^2.0.1"
5919 libnpmhook "^5.0.2"
5920 libnpx "^10.2.0"
5921 lock-verify "^2.1.0"
5922 lockfile "^1.0.4"
5923 lodash._baseuniq "~4.6.0"
5924 lodash.clonedeep "~4.5.0"
5925 lodash.union "~4.6.0"
5926 lodash.uniq "~4.5.0"
5927 lodash.without "~4.4.0"
5928 lru-cache "^4.1.5"
5929 meant "~1.0.1"
5930 mississippi "^3.0.0"
5931 mkdirp "~0.5.1"
5932 move-concurrently "^1.0.1"
5933 node-gyp "^3.8.0"
5934 nopt "~4.0.1"
5935 normalize-package-data "^2.5.0"
5936 npm-audit-report "^1.3.2"
5937 npm-cache-filename "~1.0.2"
5938 npm-install-checks "~3.0.0"
5939 npm-lifecycle "^2.1.0"
5940 npm-package-arg "^6.1.0"
5941 npm-packlist "^1.4.1"
5942 npm-pick-manifest "^2.2.3"
5943 npm-registry-fetch "^3.9.0"
5944 npm-user-validate "~1.0.0"
5945 npmlog "~4.1.2"
5946 once "~1.4.0"
5947 opener "^1.5.1"
5948 osenv "^0.1.5"
5949 pacote "^9.5.0"
5950 path-is-inside "~1.0.2"
5951 promise-inflight "~1.0.1"
5952 qrcode-terminal "^0.12.0"
5953 query-string "^6.2.0"
5954 qw "~1.0.1"
5955 read "~1.0.7"
5956 read-cmd-shim "~1.0.1"
5957 read-installed "~4.0.3"
5958 read-package-json "^2.0.13"
5959 read-package-tree "^5.2.2"
5960 readable-stream "^3.1.1"
5961 request "^2.88.0"
5962 retry "^0.12.0"
5963 rimraf "^2.6.3"
5964 safe-buffer "^5.1.2"
5965 semver "^5.6.0"
5966 sha "~2.0.1"
5967 slide "~1.1.6"
5968 sorted-object "~2.0.1"
5969 sorted-union-stream "~2.1.3"
5970 ssri "^6.0.1"
5971 stringify-package "^1.0.0"
5972 tar "^4.4.8"
5973 text-table "~0.2.0"
5974 tiny-relative-date "^1.3.0"
5975 uid-number "0.0.6"
5976 umask "~1.1.0"
5977 unique-filename "^1.1.1"
5978 unpipe "~1.0.0"
5979 update-notifier "^2.5.0"
5980 uuid "^3.3.2"
5981 validate-npm-package-license "^3.0.4"
5982 validate-npm-package-name "~3.0.0"
5983 which "^1.3.1"
5984 worker-farm "^1.6.0"
5985 write-file-atomic "^2.4.2"
5986
5987"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.1, npmlog@^4.0.2, npmlog@^4.1.2, npmlog@~4.1.2:
5988 version "4.1.2" 5057 version "4.1.2"
5989 resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" 5058 resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
5990 integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== 5059 integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
@@ -6041,9 +5110,9 @@ object-copy@^0.1.0:
6041 kind-of "^3.0.3" 5110 kind-of "^3.0.3"
6042 5111
6043object-keys@^1.0.11, object-keys@^1.0.12: 5112object-keys@^1.0.11, object-keys@^1.0.12:
6044 version "1.1.0" 5113 version "1.1.1"
6045 resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.0.tgz#11bd22348dd2e096a045ab06f6c85bcc340fa032" 5114 resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
6046 integrity sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg== 5115 integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
6047 5116
6048object-visit@^1.0.0: 5117object-visit@^1.0.0:
6049 version "1.0.1" 5118 version "1.0.1"
@@ -6089,7 +5158,7 @@ on-headers@~1.0.1:
6089 resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" 5158 resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
6090 integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== 5159 integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
6091 5160
6092once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0, once@~1.4.0: 5161once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0:
6093 version "1.4.0" 5162 version "1.4.0"
6094 resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 5163 resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
6095 integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 5164 integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
@@ -6134,11 +5203,6 @@ openapi-schema-validation@^0.4.2:
6134 jsonschema-draft4 "^1.0.0" 5203 jsonschema-draft4 "^1.0.0"
6135 swagger-schema-official "2.0.0-bab6bed" 5204 swagger-schema-official "2.0.0-bab6bed"
6136 5205
6137opener@^1.5.1:
6138 version "1.5.1"
6139 resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
6140 integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==
6141
6142optionator@^0.8.1: 5206optionator@^0.8.1:
6143 version "0.8.2" 5207 version "0.8.2"
6144 resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 5208 resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
@@ -6161,16 +5225,7 @@ os-homedir@^1.0.0, os-homedir@^1.0.1:
6161 resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 5225 resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
6162 integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= 5226 integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
6163 5227
6164os-locale@^2.0.0: 5228os-locale@^3.0.0, os-locale@^3.1.0:
6165 version "2.1.0"
6166 resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2"
6167 integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==
6168 dependencies:
6169 execa "^0.7.0"
6170 lcid "^1.0.0"
6171 mem "^1.1.0"
6172
6173os-locale@^3.0.0:
6174 version "3.1.0" 5229 version "3.1.0"
6175 resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" 5230 resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
6176 integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== 5231 integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==
@@ -6184,7 +5239,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2:
6184 resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 5239 resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
6185 integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= 5240 integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
6186 5241
6187osenv@0, osenv@^0.1.4, osenv@^0.1.5: 5242osenv@^0.1.4:
6188 version "0.1.5" 5243 version "0.1.5"
6189 resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" 5244 resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
6190 integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== 5245 integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
@@ -6203,31 +5258,17 @@ p-finally@^1.0.0:
6203 integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= 5258 integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
6204 5259
6205p-is-promise@^2.0.0: 5260p-is-promise@^2.0.0:
6206 version "2.0.0" 5261 version "2.1.0"
6207 resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5" 5262 resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
6208 integrity sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg== 5263 integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
6209
6210p-limit@^1.1.0:
6211 version "1.3.0"
6212 resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
6213 integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
6214 dependencies:
6215 p-try "^1.0.0"
6216 5264
6217p-limit@^2.0.0: 5265p-limit@^2.0.0, p-limit@^2.2.0:
6218 version "2.2.0" 5266 version "2.2.0"
6219 resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" 5267 resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2"
6220 integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== 5268 integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==
6221 dependencies: 5269 dependencies:
6222 p-try "^2.0.0" 5270 p-try "^2.0.0"
6223 5271
6224p-locate@^2.0.0:
6225 version "2.0.0"
6226 resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
6227 integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
6228 dependencies:
6229 p-limit "^1.1.0"
6230
6231p-locate@^3.0.0: 5272p-locate@^3.0.0:
6232 version "3.0.0" 5273 version "3.0.0"
6233 resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" 5274 resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
@@ -6235,28 +5276,30 @@ p-locate@^3.0.0:
6235 dependencies: 5276 dependencies:
6236 p-limit "^2.0.0" 5277 p-limit "^2.0.0"
6237 5278
5279p-locate@^4.1.0:
5280 version "4.1.0"
5281 resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
5282 integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
5283 dependencies:
5284 p-limit "^2.2.0"
5285
6238p-map@^1.1.1: 5286p-map@^1.1.1:
6239 version "1.2.0" 5287 version "1.2.0"
6240 resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" 5288 resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
6241 integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== 5289 integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==
6242 5290
6243p-map@^2.0.0: 5291p-map@^2.0.0:
6244 version "2.0.0" 5292 version "2.1.0"
6245 resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.0.0.tgz#be18c5a5adeb8e156460651421aceca56c213a50" 5293 resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
6246 integrity sha512-GO107XdrSUmtHxVoi60qc9tUl/KkNKm+X2CF4P9amalpGxv5YqVPJNfSb0wcA+syCopkZvYYIzW8OVTQW59x/w== 5294 integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
6247 5295
6248p-timeout@^2.0.1: 5296p-timeout@^3.1.0:
6249 version "2.0.1" 5297 version "3.1.0"
6250 resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" 5298 resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.1.0.tgz#198c1f503bb973e9b9727177a276c80afd6851f3"
6251 integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== 5299 integrity sha512-C27DYI+tCroT8J8cTEyySGydl2B7FlxrGNF5/wmMbl1V+jeehUCzEE/BVgzRebdm2K3ZitKOKx8YbdFumDyYmw==
6252 dependencies: 5300 dependencies:
6253 p-finally "^1.0.0" 5301 p-finally "^1.0.0"
6254 5302
6255p-try@^1.0.0:
6256 version "1.0.0"
6257 resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
6258 integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
6259
6260p-try@^2.0.0: 5303p-try@^2.0.0:
6261 version "2.2.0" 5304 version "2.2.0"
6262 resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 5305 resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
@@ -6284,48 +5327,6 @@ packet-reader@1.0.0:
6284 resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" 5327 resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74"
6285 integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== 5328 integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==
6286 5329
6287pacote@^9.1.0, pacote@^9.2.3, pacote@^9.5.0:
6288 version "9.5.0"
6289 resolved "https://registry.yarnpkg.com/pacote/-/pacote-9.5.0.tgz#85f3013a3f6dd51c108b0ccabd3de8102ddfaeda"
6290 integrity sha512-aUplXozRbzhaJO48FaaeClmN+2Mwt741MC6M3bevIGZwdCaP7frXzbUOfOWa91FPHoLITzG0hYaKY363lxO3bg==
6291 dependencies:
6292 bluebird "^3.5.3"
6293 cacache "^11.3.2"
6294 figgy-pudding "^3.5.1"
6295 get-stream "^4.1.0"
6296 glob "^7.1.3"
6297 lru-cache "^5.1.1"
6298 make-fetch-happen "^4.0.1"
6299 minimatch "^3.0.4"
6300 minipass "^2.3.5"
6301 mississippi "^3.0.0"
6302 mkdirp "^0.5.1"
6303 normalize-package-data "^2.4.0"
6304 npm-package-arg "^6.1.0"
6305 npm-packlist "^1.1.12"
6306 npm-pick-manifest "^2.2.3"
6307 npm-registry-fetch "^3.8.0"
6308 osenv "^0.1.5"
6309 promise-inflight "^1.0.1"
6310 promise-retry "^1.1.1"
6311 protoduck "^5.0.1"
6312 rimraf "^2.6.2"
6313 safe-buffer "^5.1.2"
6314 semver "^5.6.0"
6315 ssri "^6.0.1"
6316 tar "^4.4.8"
6317 unique-filename "^1.1.1"
6318 which "^1.3.1"
6319
6320parallel-transform@^1.1.0:
6321 version "1.1.0"
6322 resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
6323 integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=
6324 dependencies:
6325 cyclist "~0.2.2"
6326 inherits "^2.0.3"
6327 readable-stream "^2.1.5"
6328
6329parse-json@^4.0.0: 5330parse-json@^4.0.0:
6330 version "4.0.0" 5331 version "4.0.0"
6331 resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" 5332 resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
@@ -6339,11 +5340,6 @@ parse-numeric-range@^0.0.2:
6339 resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4" 5340 resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4"
6340 integrity sha1-tPCdQTx6282Yf26SM8e0shDJOOQ= 5341 integrity sha1-tPCdQTx6282Yf26SM8e0shDJOOQ=
6341 5342
6342parse-passwd@^1.0.0:
6343 version "1.0.0"
6344 resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
6345 integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
6346
6347parse-torrent@^6.0.0, parse-torrent@^6.1.2: 5343parse-torrent@^6.0.0, parse-torrent@^6.1.2:
6348 version "6.1.2" 5344 version "6.1.2"
6349 resolved "https://registry.yarnpkg.com/parse-torrent/-/parse-torrent-6.1.2.tgz#99da5bdd23435a1cb7e8e7a63847c4efb21b1956" 5345 resolved "https://registry.yarnpkg.com/parse-torrent/-/parse-torrent-6.1.2.tgz#99da5bdd23435a1cb7e8e7a63847c4efb21b1956"
@@ -6378,10 +5374,10 @@ parseuri@0.0.5:
6378 dependencies: 5374 dependencies:
6379 better-assert "~1.0.0" 5375 better-assert "~1.0.0"
6380 5376
6381parseurl@~1.3.1, parseurl@~1.3.2: 5377parseurl@~1.3.1, parseurl@~1.3.3:
6382 version "1.3.2" 5378 version "1.3.3"
6383 resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" 5379 resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
6384 integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= 5380 integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
6385 5381
6386pascalcase@^0.1.1: 5382pascalcase@^0.1.1:
6387 version "0.1.1" 5383 version "0.1.1"
@@ -6410,7 +5406,7 @@ path-is-absolute@^1.0.0:
6410 resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 5406 resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
6411 integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 5407 integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
6412 5408
6413path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.2: 5409path-is-inside@^1.0.1, path-is-inside@^1.0.2:
6414 version "1.0.2" 5410 version "1.0.2"
6415 resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 5411 resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
6416 integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= 5412 integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
@@ -6482,20 +5478,20 @@ pg-pool@^2.0.4:
6482 integrity sha512-hod2zYQxM8Gt482q+qONGTYcg/qVcV32VHVPtktbBJs0us3Dj7xibISw0BAAXVMCzt8A/jhfJvpZaxUlqtqs0g== 5478 integrity sha512-hod2zYQxM8Gt482q+qONGTYcg/qVcV32VHVPtktbBJs0us3Dj7xibISw0BAAXVMCzt8A/jhfJvpZaxUlqtqs0g==
6483 5479
6484pg-types@~2.0.0: 5480pg-types@~2.0.0:
6485 version "2.0.0" 5481 version "2.0.1"
6486 resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.0.0.tgz#038ddc302a0340efcdb46d0581cc7caa2303cbba" 5482 resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.0.1.tgz#b8585a37f2a9c7b386747e44574799549e5f4933"
6487 integrity sha512-THUD7gQll5tys+5eQ8Rvs7DjHiIC3bLqixk3gMN9Hu8UrCBAOjf35FoI39rTGGc3lM2HU/R+Knpxvd11mCwOMA== 5483 integrity sha512-b7y6QM1VF5nOeX9ukMQ0h8a9z89mojrBHXfJeSug4mhL0YpxNBm83ot2TROyoAmX/ZOX3UbwVO4EbH7i1ZZNiw==
6488 dependencies: 5484 dependencies:
6489 pg-int8 "1.0.1" 5485 pg-int8 "1.0.1"
6490 postgres-array "~2.0.0" 5486 postgres-array "~2.0.0"
6491 postgres-bytea "~1.0.0" 5487 postgres-bytea "~1.0.0"
6492 postgres-date "~1.0.0" 5488 postgres-date "~1.0.4"
6493 postgres-interval "^1.1.0" 5489 postgres-interval "^1.1.0"
6494 5490
6495pg@^7.4.1: 5491pg@^7.4.1:
6496 version "7.9.0" 5492 version "7.11.0"
6497 resolved "https://registry.yarnpkg.com/pg/-/pg-7.9.0.tgz#04f0024d810544463f47dbb5aada2486aa7dcc36" 5493 resolved "https://registry.yarnpkg.com/pg/-/pg-7.11.0.tgz#a8b9ae9cf19199b7952b72957573d0a9c5e67c0c"
6498 integrity sha512-GkzteBFpsIoIBCSuomqik3IGvhqAtTr32jclR24RmUg170Jrn6ypwR97YalFHrsE1iaW8T0aAH13dmij8QUQ0g== 5494 integrity sha512-YO4V7vCmEMGoF390LJaFaohWNKaA2ayoQOEZmiHVcAUF+YsRThpf/TaKCgSvsSE7cDm37Q/Cy3Gz41xiX/XjTw==
6499 dependencies: 5495 dependencies:
6500 buffer-writer "2.0.0" 5496 buffer-writer "2.0.0"
6501 packet-reader "1.0.0" 5497 packet-reader "1.0.0"
@@ -6541,12 +5537,12 @@ pinkie@^2.0.0:
6541 resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 5537 resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
6542 integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= 5538 integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
6543 5539
6544pkg-dir@^3.0.0: 5540pkg-dir@^4.1.0:
6545 version "3.0.0" 5541 version "4.2.0"
6546 resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" 5542 resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
6547 integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== 5543 integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
6548 dependencies: 5544 dependencies:
6549 find-up "^3.0.0" 5545 find-up "^4.0.0"
6550 5546
6551pkginfo@0.3.x: 5547pkginfo@0.3.x:
6552 version "0.3.1" 5548 version "0.3.1"
@@ -6590,10 +5586,10 @@ postgres-bytea@~1.0.0:
6590 resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" 5586 resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35"
6591 integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= 5587 integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=
6592 5588
6593postgres-date@~1.0.0: 5589postgres-date@~1.0.4:
6594 version "1.0.3" 5590 version "1.0.4"
6595 resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.3.tgz#e2d89702efdb258ff9d9cee0fe91bd06975257a8" 5591 resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.4.tgz#1c2728d62ef1bff49abdd35c1f86d4bdf118a728"
6596 integrity sha1-4tiXAu/bJY/52c7g/pG9BpdSV6g= 5592 integrity sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA==
6597 5593
6598postgres-interval@^1.1.0: 5594postgres-interval@^1.1.0:
6599 version "1.2.0" 5595 version "1.2.0"
@@ -6602,10 +5598,10 @@ postgres-interval@^1.1.0:
6602 dependencies: 5598 dependencies:
6603 xtend "^4.0.0" 5599 xtend "^4.0.0"
6604 5600
6605prebuild-install@^5.2.5: 5601prebuild-install@^5.3.0:
6606 version "5.2.5" 5602 version "5.3.0"
6607 resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.2.5.tgz#c7485911fe98950b7f7cd15bb9daee11b875cc44" 5603 resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.0.tgz#58b4d8344e03590990931ee088dd5401b03004c8"
6608 integrity sha512-6uZgMVg7yDfqlP5CPurVhtq3hUKBFNufiar4J5hZrlHTo59DDBEtyxw01xCdFss9j0Zb9+qzFVf/s4niayba3w== 5604 integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg==
6609 dependencies: 5605 dependencies:
6610 detect-libc "^1.0.3" 5606 detect-libc "^1.0.3"
6611 expand-template "^2.0.3" 5607 expand-template "^2.0.3"
@@ -6644,19 +5640,6 @@ progress@^1.1.8:
6644 resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" 5640 resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
6645 integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74= 5641 integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=
6646 5642
6647promise-inflight@^1.0.1, promise-inflight@~1.0.1:
6648 version "1.0.1"
6649 resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
6650 integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
6651
6652promise-retry@^1.1.1:
6653 version "1.1.1"
6654 resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d"
6655 integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=
6656 dependencies:
6657 err-code "^1.0.0"
6658 retry "^0.10.0"
6659
6660promise.prototype.finally@^3.1.0: 5643promise.prototype.finally@^3.1.0:
6661 version "3.1.0" 5644 version "3.1.0"
6662 resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e" 5645 resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e"
@@ -6687,30 +5670,11 @@ prompt@^1.0.0:
6687 utile "0.3.x" 5670 utile "0.3.x"
6688 winston "2.1.x" 5671 winston "2.1.x"
6689 5672
6690promzard@^0.3.0:
6691 version "0.3.0"
6692 resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee"
6693 integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=
6694 dependencies:
6695 read "1"
6696
6697property-expr@^1.5.0: 5673property-expr@^1.5.0:
6698 version "1.5.1" 5674 version "1.5.1"
6699 resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f" 5675 resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f"
6700 integrity sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g== 5676 integrity sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==
6701 5677
6702proto-list@~1.2.1:
6703 version "1.2.4"
6704 resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
6705 integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=
6706
6707protoduck@^5.0.1:
6708 version "5.0.1"
6709 resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f"
6710 integrity sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==
6711 dependencies:
6712 genfun "^5.0.0"
6713
6714proxy-addr@~1.0.10: 5678proxy-addr@~1.0.10:
6715 version "1.0.10" 5679 version "1.0.10"
6716 resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.0.10.tgz#0d40a82f801fc355567d2ecb65efe3f077f121c5" 5680 resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.0.10.tgz#0d40a82f801fc355567d2ecb65efe3f077f121c5"
@@ -6719,18 +5683,13 @@ proxy-addr@~1.0.10:
6719 forwarded "~0.1.0" 5683 forwarded "~0.1.0"
6720 ipaddr.js "1.0.5" 5684 ipaddr.js "1.0.5"
6721 5685
6722proxy-addr@~2.0.4: 5686proxy-addr@~2.0.5:
6723 version "2.0.4" 5687 version "2.0.5"
6724 resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" 5688 resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
6725 integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== 5689 integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
6726 dependencies: 5690 dependencies:
6727 forwarded "~0.1.2" 5691 forwarded "~0.1.2"
6728 ipaddr.js "1.8.0" 5692 ipaddr.js "1.9.0"
6729
6730prr@~1.0.1:
6731 version "1.0.1"
6732 resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
6733 integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
6734 5693
6735pseudomap@^1.0.2: 5694pseudomap@^1.0.2:
6736 version "1.0.2" 5695 version "1.0.2"
@@ -6738,14 +5697,14 @@ pseudomap@^1.0.2:
6738 integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= 5697 integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
6739 5698
6740psl@^1.1.24: 5699psl@^1.1.24:
6741 version "1.1.31" 5700 version "1.1.32"
6742 resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" 5701 resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.32.tgz#3f132717cf2f9c169724b2b6caf373cf694198db"
6743 integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== 5702 integrity sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==
6744 5703
6745pstree.remy@^1.1.6: 5704pstree.remy@^1.1.6:
6746 version "1.1.6" 5705 version "1.1.7"
6747 resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.6.tgz#73a55aad9e2d95814927131fbf4dc1b62d259f47" 5706 resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.7.tgz#c76963a28047ed61542dc361aa26ee55a7fa15f3"
6748 integrity sha512-NdF35+QsqD7EgNEI5mkI/X+UwaxVEbQaz9f4IooEmMUv6ZPmlTQYGjBPJGgrlzNdjSvIy4MWMg6Q6vCgBO2K+w== 5707 integrity sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==
6749 5708
6750pump@^1.0.0: 5709pump@^1.0.0:
6751 version "1.0.3" 5710 version "1.0.3"
@@ -6790,44 +5749,25 @@ punycode@^2.1.0:
6790 resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 5749 resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
6791 integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 5750 integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
6792 5751
6793qrcode-terminal@^0.12.0:
6794 version "0.12.0"
6795 resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819"
6796 integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==
6797
6798qs@4.0.0: 5752qs@4.0.0:
6799 version "4.0.0" 5753 version "4.0.0"
6800 resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" 5754 resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607"
6801 integrity sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc= 5755 integrity sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc=
6802 5756
6803qs@6.5.2, qs@~6.5.2: 5757qs@6.7.0, qs@^6.5.1:
6804 version "6.5.2"
6805 resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
6806 integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
6807
6808qs@^6.5.1:
6809 version "6.7.0" 5758 version "6.7.0"
6810 resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" 5759 resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
6811 integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== 5760 integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
6812 5761
6813query-string@^6.2.0: 5762qs@~6.5.2:
6814 version "6.4.2" 5763 version "6.5.2"
6815 resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.4.2.tgz#8be1dbd105306aebf86022144f575a29d516b713" 5764 resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
6816 integrity sha512-DfJqAen17LfLA3rQ+H5S4uXphrF+ANU1lT2ijds4V/Tj4gZxA3gx5/tg1bz7kYCmwna7LyJNCYqO7jNRzo3aLw== 5765 integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
6817 dependencies:
6818 decode-uri-component "^0.2.0"
6819 split-on-first "^1.0.0"
6820 strict-uri-encode "^2.0.0"
6821
6822qw@~1.0.1:
6823 version "1.0.1"
6824 resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4"
6825 integrity sha1-77/cdA+a0FQwRCassYNBLMi5ltQ=
6826 5766
6827random-access-file@^2.0.1: 5767random-access-file@^2.0.1:
6828 version "2.1.0" 5768 version "2.1.2"
6829 resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-2.1.0.tgz#7b3b6623d47e2f89282e77f0c9c9ae6da3cd9039" 5769 resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-2.1.2.tgz#eeb32e50b9831f32060516862381152ae4e05aa6"
6830 integrity sha512-W2hY3DboLETMclybTVzyqCNVKx1MjqUwZPzkpkkMD2t9mbGEtkV2SKWPqAJ/FTrAtnWB7aGwl0NDUS82da0KdQ== 5770 integrity sha512-dZo7HEcEPbZ/6XLXC4GXypiWvFbXVkdeMrJTi0B94pBJwddt/AvJh8GaQhso6KGYROGYCI/VWdHbmRDtkwT9pQ==
6831 dependencies: 5771 dependencies:
6832 mkdirp "^0.5.1" 5772 mkdirp "^0.5.1"
6833 random-access-storage "^1.1.1" 5773 random-access-storage "^1.1.1"
@@ -6851,10 +5791,10 @@ randombytes@^2.0.3, randombytes@^2.0.5:
6851 dependencies: 5791 dependencies:
6852 safe-buffer "^5.1.0" 5792 safe-buffer "^5.1.0"
6853 5793
6854range-parser@^1.2.0, range-parser@~1.2.0: 5794range-parser@^1.2.0, range-parser@~1.2.1:
6855 version "1.2.0" 5795 version "1.2.1"
6856 resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" 5796 resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
6857 integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= 5797 integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
6858 5798
6859range-parser@~1.0.3: 5799range-parser@~1.0.3:
6860 version "1.0.3" 5800 version "1.0.3"
@@ -6868,14 +5808,14 @@ range-slice-stream@^2.0.0:
6868 dependencies: 5808 dependencies:
6869 readable-stream "^3.0.2" 5809 readable-stream "^3.0.2"
6870 5810
6871raw-body@2.3.3: 5811raw-body@2.4.0:
6872 version "2.3.3" 5812 version "2.4.0"
6873 resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" 5813 resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
6874 integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== 5814 integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
6875 dependencies: 5815 dependencies:
6876 bytes "3.0.0" 5816 bytes "3.1.0"
6877 http-errors "1.6.3" 5817 http-errors "1.7.2"
6878 iconv-lite "0.4.23" 5818 iconv-lite "0.4.24"
6879 unpipe "1.0.0" 5819 unpipe "1.0.0"
6880 5820
6881rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: 5821rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
@@ -6898,50 +5838,6 @@ rdf-canonize@^0.2.1:
6898 node-forge "^0.7.1" 5838 node-forge "^0.7.1"
6899 semver "^5.4.1" 5839 semver "^5.4.1"
6900 5840
6901read-cmd-shim@^1.0.1, read-cmd-shim@~1.0.1:
6902 version "1.0.1"
6903 resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.1.tgz#2d5d157786a37c055d22077c32c53f8329e91c7b"
6904 integrity sha1-LV0Vd4ajfAVdIgd8MsU/gynpHHs=
6905 dependencies:
6906 graceful-fs "^4.1.2"
6907
6908read-installed@~4.0.3:
6909 version "4.0.3"
6910 resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067"
6911 integrity sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=
6912 dependencies:
6913 debuglog "^1.0.1"
6914 read-package-json "^2.0.0"
6915 readdir-scoped-modules "^1.0.0"
6916 semver "2 || 3 || 4 || 5"
6917 slide "~1.1.3"
6918 util-extend "^1.0.1"
6919 optionalDependencies:
6920 graceful-fs "^4.1.2"
6921
6922"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@^2.0.13:
6923 version "2.0.13"
6924 resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.0.13.tgz#2e82ebd9f613baa6d2ebe3aa72cefe3f68e41f4a"
6925 integrity sha512-/1dZ7TRZvGrYqE0UAfN6qQb5GYBsNcqS1C0tNK601CFOJmtHI7NIGXwetEPU/OtoFHZL3hDxm4rolFFVE9Bnmg==
6926 dependencies:
6927 glob "^7.1.1"
6928 json-parse-better-errors "^1.0.1"
6929 normalize-package-data "^2.0.0"
6930 slash "^1.0.0"
6931 optionalDependencies:
6932 graceful-fs "^4.1.2"
6933
6934read-package-tree@^5.2.2:
6935 version "5.2.2"
6936 resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.2.2.tgz#4b6a0ef2d943c1ea36a578214c9a7f6b7424f7a8"
6937 integrity sha512-rW3XWUUkhdKmN2JKB4FL563YAgtINifso5KShykufR03nJ5loGFlkUMe1g/yxmqX073SoYYTsgXu7XdDinKZuA==
6938 dependencies:
6939 debuglog "^1.0.1"
6940 dezalgo "^1.0.0"
6941 once "^1.3.0"
6942 read-package-json "^2.0.0"
6943 readdir-scoped-modules "^1.0.0"
6944
6945read-pkg@^4.0.1: 5841read-pkg@^4.0.1:
6946 version "4.0.1" 5842 version "4.0.1"
6947 resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" 5843 resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237"
@@ -6951,27 +5847,24 @@ read-pkg@^4.0.1:
6951 parse-json "^4.0.0" 5847 parse-json "^4.0.0"
6952 pify "^3.0.0" 5848 pify "^3.0.0"
6953 5849
6954read@1, read@1.0.x, read@~1.0.1, read@~1.0.7: 5850read-pkg@^5.1.1:
5851 version "5.1.1"
5852 resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.1.1.tgz#5cf234dde7a405c90c88a519ab73c467e9cb83f5"
5853 integrity sha512-dFcTLQi6BZ+aFUaICg7er+/usEoqFdQxiEBsEMNGoipenihtxxtdrQuBXvyANCEI8VuUIVYFgeHGx9sLLvim4w==
5854 dependencies:
5855 "@types/normalize-package-data" "^2.4.0"
5856 normalize-package-data "^2.5.0"
5857 parse-json "^4.0.0"
5858 type-fest "^0.4.1"
5859
5860read@1.0.x:
6955 version "1.0.7" 5861 version "1.0.7"
6956 resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" 5862 resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4"
6957 integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= 5863 integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=
6958 dependencies: 5864 dependencies:
6959 mute-stream "~0.0.4" 5865 mute-stream "~0.0.4"
6960 5866
6961"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.3, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.2, readable-stream@^2.3.4, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: 5867readable-stream@1.1.x, "readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.1.13-1:
6962 version "2.3.6"
6963 resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
6964 integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
6965 dependencies:
6966 core-util-is "~1.0.0"
6967 inherits "~2.0.3"
6968 isarray "~1.0.0"
6969 process-nextick-args "~2.0.0"
6970 safe-buffer "~5.1.1"
6971 string_decoder "~1.1.1"
6972 util-deprecate "~1.0.1"
6973
6974readable-stream@1.1.x, "readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.1.13-1, readable-stream@~1.1.10:
6975 version "1.1.14" 5868 version "1.1.14"
6976 resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" 5869 resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
6977 integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= 5870 integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
@@ -6991,10 +5884,23 @@ readable-stream@1.1.x, "readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1
6991 isarray "0.0.1" 5884 isarray "0.0.1"
6992 string_decoder "~0.10.x" 5885 string_decoder "~0.10.x"
6993 5886
5887readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.3, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.2, readable-stream@^2.3.4, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
5888 version "2.3.6"
5889 resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
5890 integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
5891 dependencies:
5892 core-util-is "~1.0.0"
5893 inherits "~2.0.3"
5894 isarray "~1.0.0"
5895 process-nextick-args "~2.0.0"
5896 safe-buffer "~5.1.1"
5897 string_decoder "~1.1.1"
5898 util-deprecate "~1.0.1"
5899
6994readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1: 5900readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1:
6995 version "3.3.0" 5901 version "3.4.0"
6996 resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.3.0.tgz#cb8011aad002eb717bf040291feba8569c986fb9" 5902 resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc"
6997 integrity sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw== 5903 integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==
6998 dependencies: 5904 dependencies:
6999 inherits "^2.0.3" 5905 inherits "^2.0.3"
7000 string_decoder "^1.1.1" 5906 string_decoder "^1.1.1"
@@ -7007,16 +5913,6 @@ readable-wrap@^1.0.0:
7007 dependencies: 5913 dependencies:
7008 readable-stream "^1.1.13-1" 5914 readable-stream "^1.1.13-1"
7009 5915
7010readdir-scoped-modules@^1.0.0:
7011 version "1.0.2"
7012 resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747"
7013 integrity sha1-n6+jfShr5dksuuve4DDcm19AZ0c=
7014 dependencies:
7015 debuglog "^1.0.1"
7016 dezalgo "^1.0.0"
7017 graceful-fs "^4.1.2"
7018 once "^1.3.0"
7019
7020readdirp@^2.2.1: 5916readdirp@^2.2.1:
7021 version "2.2.1" 5917 version "2.2.1"
7022 resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" 5918 resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
@@ -7040,11 +5936,16 @@ record-cache@^1.0.2:
7040 resolved "https://registry.yarnpkg.com/record-cache/-/record-cache-1.1.0.tgz#f8a467a691a469584b26e88d36b18afdb3932037" 5936 resolved "https://registry.yarnpkg.com/record-cache/-/record-cache-1.1.0.tgz#f8a467a691a469584b26e88d36b18afdb3932037"
7041 integrity sha512-u8rbtLEJV7HRacl/ZYwSBFD8NFyB3PfTTfGLP37IW3hftQCwu6z4Q2RLyxo1YJUNRTEzJfpLpGwVuEYdaIkG9Q== 5937 integrity sha512-u8rbtLEJV7HRacl/ZYwSBFD8NFyB3PfTTfGLP37IW3hftQCwu6z4Q2RLyxo1YJUNRTEzJfpLpGwVuEYdaIkG9Q==
7042 5938
7043redis-commands@1.4.0, redis-commands@^1.2.0: 5939redis-commands@1.4.0:
7044 version "1.4.0" 5940 version "1.4.0"
7045 resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.4.0.tgz#52f9cf99153efcce56a8f86af986bd04e988602f" 5941 resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.4.0.tgz#52f9cf99153efcce56a8f86af986bd04e988602f"
7046 integrity sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw== 5942 integrity sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==
7047 5943
5944redis-commands@^1.2.0:
5945 version "1.5.0"
5946 resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.5.0.tgz#80d2e20698fe688f227127ff9e5164a7dd17e785"
5947 integrity sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg==
5948
7048redis-errors@^1.0.0, redis-errors@^1.2.0: 5949redis-errors@^1.0.0, redis-errors@^1.2.0:
7049 version "1.2.0" 5950 version "1.2.0"
7050 resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" 5951 resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad"
@@ -7071,20 +5972,20 @@ redis@^2.8.0:
7071 redis-commands "^1.2.0" 5972 redis-commands "^1.2.0"
7072 redis-parser "^2.6.0" 5973 redis-parser "^2.6.0"
7073 5974
7074referrer-policy@1.1.0: 5975referrer-policy@1.2.0:
7075 version "1.1.0" 5976 version "1.2.0"
7076 resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.1.0.tgz#35774eb735bf50fb6c078e83334b472350207d79" 5977 resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.2.0.tgz#b99cfb8b57090dc454895ef897a4cc35ef67a98e"
7077 integrity sha1-NXdOtzW/UPtsB46DM0tHI1AgfXk= 5978 integrity sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==
7078 5979
7079reflect-metadata@^0.1.12: 5980reflect-metadata@^0.1.12:
7080 version "0.1.13" 5981 version "0.1.13"
7081 resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" 5982 resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
7082 integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== 5983 integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
7083 5984
7084regenerator-runtime@^0.12.0: 5985regenerator-runtime@^0.13.2:
7085 version "0.12.1" 5986 version "0.13.2"
7086 resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" 5987 resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
7087 integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== 5988 integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
7088 5989
7089regex-not@^1.0.0, regex-not@^1.0.2: 5990regex-not@^1.0.0, regex-not@^1.0.2:
7090 version "1.0.2" 5991 version "1.0.2"
@@ -7135,7 +6036,7 @@ repeat-string@^1.6.1:
7135 resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 6036 resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
7136 integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= 6037 integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
7137 6038
7138request@^2.81.0, request@^2.83.0, request@^2.87.0, request@^2.88.0, request@~2.88.0: 6039request@^2.81.0, request@^2.83.0, request@~2.88.0:
7139 version "2.88.0" 6040 version "2.88.0"
7140 resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" 6041 resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
7141 integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== 6042 integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
@@ -7171,6 +6072,11 @@ require-main-filename@^1.0.1:
7171 resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" 6072 resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
7172 integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= 6073 integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
7173 6074
6075require-main-filename@^2.0.0:
6076 version "2.0.0"
6077 resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
6078 integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
6079
7174require-uncached@^1.0.2: 6080require-uncached@^1.0.2:
7175 version "1.0.3" 6081 version "1.0.3"
7176 resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" 6082 resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
@@ -7179,14 +6085,6 @@ require-uncached@^1.0.2:
7179 caller-path "^0.1.0" 6085 caller-path "^0.1.0"
7180 resolve-from "^1.0.0" 6086 resolve-from "^1.0.0"
7181 6087
7182resolve-dir@^1.0.0, resolve-dir@^1.0.1:
7183 version "1.0.1"
7184 resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
7185 integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
7186 dependencies:
7187 expand-tilde "^2.0.0"
7188 global-modules "^1.0.0"
7189
7190resolve-from@^1.0.0: 6088resolve-from@^1.0.0:
7191 version "1.0.1" 6089 version "1.0.1"
7192 resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" 6090 resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
@@ -7202,11 +6100,6 @@ resolve-from@^3.0.0:
7202 resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" 6100 resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
7203 integrity sha1-six699nWiBvItuZTM17rywoYh0g= 6101 integrity sha1-six699nWiBvItuZTM17rywoYh0g=
7204 6102
7205resolve-from@^4.0.0:
7206 version "4.0.0"
7207 resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
7208 integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
7209
7210resolve-pkg@^1.0.0: 6103resolve-pkg@^1.0.0:
7211 version "1.0.0" 6104 version "1.0.0"
7212 resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-1.0.0.tgz#e19a15e78aca2e124461dc92b2e3943ef93494d9" 6105 resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-1.0.0.tgz#e19a15e78aca2e124461dc92b2e3943ef93494d9"
@@ -7220,9 +6113,9 @@ resolve-url@^0.2.1:
7220 integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= 6113 integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
7221 6114
7222resolve@^1.10.0, resolve@^1.3.2: 6115resolve@^1.10.0, resolve@^1.3.2:
7223 version "1.10.0" 6116 version "1.11.1"
7224 resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" 6117 resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e"
7225 integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== 6118 integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==
7226 dependencies: 6119 dependencies:
7227 path-parse "^1.0.6" 6120 path-parse "^1.0.6"
7228 6121
@@ -7254,22 +6147,12 @@ retry-as-promised@^3.1.0:
7254 dependencies: 6147 dependencies:
7255 any-promise "^1.3.0" 6148 any-promise "^1.3.0"
7256 6149
7257retry@^0.10.0:
7258 version "0.10.1"
7259 resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4"
7260 integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=
7261
7262retry@^0.12.0:
7263 version "0.12.0"
7264 resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
7265 integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
7266
7267revalidator@0.1.x: 6150revalidator@0.1.x:
7268 version "0.1.8" 6151 version "0.1.8"
7269 resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" 6152 resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b"
7270 integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs= 6153 integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs=
7271 6154
7272rimraf@2, rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.4.2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@~2.6.2: 6155rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.4.2, rimraf@^2.6.1, rimraf@~2.6.2:
7273 version "2.6.3" 6156 version "2.6.3"
7274 resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" 6157 resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
7275 integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== 6158 integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
@@ -7298,13 +6181,6 @@ run-parallel@^1.0.0, run-parallel@^1.1.2, run-parallel@^1.1.6:
7298 resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" 6181 resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
7299 integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== 6182 integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
7300 6183
7301run-queue@^1.0.0, run-queue@^1.0.3:
7302 version "1.0.3"
7303 resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"
7304 integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=
7305 dependencies:
7306 aproba "^1.1.1"
7307
7308run-series@^1.0.2: 6184run-series@^1.0.2:
7309 version "1.1.8" 6185 version "1.1.8"
7310 resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36" 6186 resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36"
@@ -7321,9 +6197,9 @@ rx-lite@^3.1.2:
7321 integrity sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI= 6197 integrity sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=
7322 6198
7323rxjs@^6.3.3: 6199rxjs@^6.3.3:
7324 version "6.4.0" 6200 version "6.5.2"
7325 resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" 6201 resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7"
7326 integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw== 6202 integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==
7327 dependencies: 6203 dependencies:
7328 tslib "^1.9.0" 6204 tslib "^1.9.0"
7329 6205
@@ -7345,9 +6221,9 @@ safe-regex@^1.1.0:
7345 integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 6221 integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
7346 6222
7347sass-lint@^1.12.1: 6223sass-lint@^1.12.1:
7348 version "1.12.1" 6224 version "1.13.1"
7349 resolved "https://registry.yarnpkg.com/sass-lint/-/sass-lint-1.12.1.tgz#630f69c216aa206b8232fb2aa907bdf3336b6d83" 6225 resolved "https://registry.yarnpkg.com/sass-lint/-/sass-lint-1.13.1.tgz#5fd2b2792e9215272335eb0f0dc607f61e8acc8f"
7350 integrity sha1-Yw9pwhaqIGuCMvsqqQe98zNrbYM= 6226 integrity sha512-DSyah8/MyjzW2BWYmQWekYEKir44BpLqrCFsgs9iaWiVTcwZfwXHF586hh3D1n+/9ihUNMfd8iHAyb9KkGgs7Q==
7351 dependencies: 6227 dependencies:
7352 commander "^2.8.1" 6228 commander "^2.8.1"
7353 eslint "^2.7.0" 6229 eslint "^2.7.0"
@@ -7391,7 +6267,7 @@ semver-diff@^2.0.0:
7391 dependencies: 6267 dependencies:
7392 semver "^5.0.3" 6268 semver "^5.0.3"
7393 6269
7394"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: 6270"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0:
7395 version "5.7.0" 6271 version "5.7.0"
7396 resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" 6272 resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
7397 integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== 6273 integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
@@ -7401,10 +6277,10 @@ semver@4.3.2:
7401 resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" 6277 resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7"
7402 integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c= 6278 integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=
7403 6279
7404semver@~5.3.0: 6280semver@^6.0.0, semver@^6.1.1:
7405 version "5.3.0" 6281 version "6.1.1"
7406 resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" 6282 resolved "https://registry.yarnpkg.com/semver/-/semver-6.1.1.tgz#53f53da9b30b2103cd4f15eab3a18ecbcb210c9b"
7407 integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= 6283 integrity sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==
7408 6284
7409send@0.13.1: 6285send@0.13.1:
7410 version "0.13.1" 6286 version "0.13.1"
@@ -7442,10 +6318,10 @@ send@0.13.2:
7442 range-parser "~1.0.3" 6318 range-parser "~1.0.3"
7443 statuses "~1.2.1" 6319 statuses "~1.2.1"
7444 6320
7445send@0.16.2: 6321send@0.17.1:
7446 version "0.16.2" 6322 version "0.17.1"
7447 resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" 6323 resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
7448 integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== 6324 integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
7449 dependencies: 6325 dependencies:
7450 debug "2.6.9" 6326 debug "2.6.9"
7451 depd "~1.1.2" 6327 depd "~1.1.2"
@@ -7454,12 +6330,12 @@ send@0.16.2:
7454 escape-html "~1.0.3" 6330 escape-html "~1.0.3"
7455 etag "~1.8.1" 6331 etag "~1.8.1"
7456 fresh "0.5.2" 6332 fresh "0.5.2"
7457 http-errors "~1.6.2" 6333 http-errors "~1.7.2"
7458 mime "1.4.1" 6334 mime "1.6.0"
7459 ms "2.0.0" 6335 ms "2.1.1"
7460 on-finished "~2.3.0" 6336 on-finished "~2.3.0"
7461 range-parser "~1.2.0" 6337 range-parser "~1.2.1"
7462 statuses "~1.4.0" 6338 statuses "~1.5.0"
7463 6339
7464sequelize-pool@^1.0.2: 6340sequelize-pool@^1.0.2:
7465 version "1.0.2" 6341 version "1.0.2"
@@ -7475,10 +6351,10 @@ sequelize-typescript@1.0.0-beta.2:
7475 dependencies: 6351 dependencies:
7476 glob "7.1.2" 6352 glob "7.1.2"
7477 6353
7478sequelize@5.7.4: 6354sequelize@5.8.7:
7479 version "5.7.4" 6355 version "5.8.7"
7480 resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-5.7.4.tgz#1631faadff65f3a345b9757fca60429c65ba8e57" 6356 resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-5.8.7.tgz#3af2fd6051277d5fb5b32054c7f8aac4c4a04107"
7481 integrity sha512-CaVYpAgZQEsGDuZ+Oq6uIZy4pxQxscotuh5UGIaFRa0VkTIgV0IiF7vAhSv+1Wn+NvhKCvgJJ85M34BP3AdGNg== 6357 integrity sha512-1rubZM8fAyCt5ipyS+3HJ3Jbmb8WesLdPJ3jIbTD+78EbuPZILFEA5fK0mliVRBx7oM7oPULeVX0lxSRXBV1jw==
7482 dependencies: 6358 dependencies:
7483 bluebird "^3.5.0" 6359 bluebird "^3.5.0"
7484 cls-bluebird "^2.1.0" 6360 cls-bluebird "^2.1.0"
@@ -7496,15 +6372,15 @@ sequelize@5.7.4:
7496 validator "^10.11.0" 6372 validator "^10.11.0"
7497 wkx "^0.4.6" 6373 wkx "^0.4.6"
7498 6374
7499serve-static@1.13.2: 6375serve-static@1.14.1:
7500 version "1.13.2" 6376 version "1.14.1"
7501 resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" 6377 resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
7502 integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== 6378 integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
7503 dependencies: 6379 dependencies:
7504 encodeurl "~1.0.2" 6380 encodeurl "~1.0.2"
7505 escape-html "~1.0.3" 6381 escape-html "~1.0.3"
7506 parseurl "~1.3.2" 6382 parseurl "~1.3.3"
7507 send "0.16.2" 6383 send "0.17.1"
7508 6384
7509serve-static@~1.10.2: 6385serve-static@~1.10.2:
7510 version "1.10.3" 6386 version "1.10.3"
@@ -7540,32 +6416,23 @@ set-value@^2.0.0:
7540 is-plain-object "^2.0.3" 6416 is-plain-object "^2.0.3"
7541 split-string "^3.0.1" 6417 split-string "^3.0.1"
7542 6418
7543setprototypeof@1.1.0: 6419setprototypeof@1.1.1:
7544 version "1.1.0" 6420 version "1.1.1"
7545 resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" 6421 resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
7546 integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== 6422 integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
7547
7548sha@~2.0.1:
7549 version "2.0.1"
7550 resolved "https://registry.yarnpkg.com/sha/-/sha-2.0.1.tgz#6030822fbd2c9823949f8f72ed6411ee5cf25aae"
7551 integrity sha1-YDCCL70smCOUn49y7WQR7lzyWq4=
7552 dependencies:
7553 graceful-fs "^4.1.2"
7554 readable-stream "^2.0.2"
7555 6423
7556sharp@^0.22.0: 6424sharp@^0.22.0:
7557 version "0.22.0" 6425 version "0.22.1"
7558 resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.22.0.tgz#cf4cfcb019941fd06ac24555d9f5bc84536d29be" 6426 resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.22.1.tgz#a67c0e75567f03dd5a7861b901fec04072c5b0f4"
7559 integrity sha512-yInpiWYvVbE0hJylso2Q2A7QaYFBxGdSlVVHGeUf1F9JsQNAUpmaqdnX54TImgKbSCy9mQpEAoGm1pcKCZhCsQ== 6427 integrity sha512-lXzSk/FL5b/MpWrT1pQZneKe25stVjEbl6uhhJcTULm7PhmJgKKRbTDM/vtjyUuC/RLqL2PRyC4rpKwbv3soEw==
7560 dependencies: 6428 dependencies:
7561 bindings "^1.5.0" 6429 color "^3.1.1"
7562 color "^3.1.0"
7563 detect-libc "^1.0.3" 6430 detect-libc "^1.0.3"
7564 fs-copy-file-sync "^1.1.1" 6431 fs-copy-file-sync "^1.1.1"
7565 nan "^2.13.1" 6432 nan "^2.13.2"
7566 npmlog "^4.1.2" 6433 npmlog "^4.1.2"
7567 prebuild-install "^5.2.5" 6434 prebuild-install "^5.3.0"
7568 semver "^5.6.0" 6435 semver "^6.0.0"
7569 simple-get "^3.0.3" 6436 simple-get "^3.0.3"
7570 tar "^4.4.8" 6437 tar "^4.4.8"
7571 tunnel-agent "^0.6.0" 6438 tunnel-agent "^0.6.0"
@@ -7621,9 +6488,9 @@ simple-get@^3.0.0, simple-get@^3.0.1, simple-get@^3.0.3:
7621 simple-concat "^1.0.0" 6488 simple-concat "^1.0.0"
7622 6489
7623simple-git@^1.85.0: 6490simple-git@^1.85.0:
7624 version "1.110.0" 6491 version "1.113.0"
7625 resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.110.0.tgz#54eb179089d055a7783d32399246cebc9d9933e9" 6492 resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.113.0.tgz#668989728a1e9cf4ec6c72b69ea2eecc93489bea"
7626 integrity sha512-UYY0rQkknk0P5eb+KW+03F4TevZ9ou0H+LoGaj7iiVgpnZH4wdj/HTViy/1tNNkmIPcmtxuBqXWiYt2YwlRKOQ== 6493 integrity sha512-i9WVsrK2u0G/cASI9nh7voxOk9mhanWY9eGtWBDSYql6m49Yk5/Fan6uZsDr/xmzv8n+eQ8ahKCoEr8cvU3h+g==
7627 dependencies: 6494 dependencies:
7628 debug "^4.0.1" 6495 debug "^4.0.1"
7629 6496
@@ -7664,39 +6531,24 @@ simple-websocket@^7.0.1:
7664 ws "^6.0.0" 6531 ws "^6.0.0"
7665 6532
7666sitemap@^2.1.0: 6533sitemap@^2.1.0:
7667 version "2.1.0" 6534 version "2.2.0"
7668 resolved "https://registry.yarnpkg.com/sitemap/-/sitemap-2.1.0.tgz#1633cb88c196d755ad94becfb1c1bcacc6d3425a" 6535 resolved "https://registry.yarnpkg.com/sitemap/-/sitemap-2.2.0.tgz#98b8502762c5d7e8c77c9be5061dce85b326f1b0"
7669 integrity sha512-AkfA7RDVCITQo+j5CpXsMJlZ/8ENO2NtgMHYIh+YMvex2Hao/oe3MQgNa03p0aWY6srCfUA1Q02OgiWCAiuccA== 6536 integrity sha512-9Zoi3UBhSIt5jWENDRUbzsqLMJ+Fha3P2aQ2PRghmh0FOivtHsC4FAJdkAEKHvATajd74BWp/57Yh7kz/UA53Q==
7670 dependencies: 6537 dependencies:
7671 lodash "^4.17.10" 6538 lodash "^4.17.10"
7672 url-join "^4.0.0" 6539 url-join "^4.0.0"
7673 xmlbuilder "^10.0.0" 6540 xmlbuilder "^10.0.0"
7674 6541
7675slash@^1.0.0: 6542slash@^3.0.0:
7676 version "1.0.0" 6543 version "3.0.0"
7677 resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" 6544 resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
7678 integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= 6545 integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
7679
7680slash@^2.0.0:
7681 version "2.0.0"
7682 resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
7683 integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
7684 6546
7685slice-ansi@0.0.4: 6547slice-ansi@0.0.4:
7686 version "0.0.4" 6548 version "0.0.4"
7687 resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" 6549 resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
7688 integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU= 6550 integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=
7689 6551
7690slide@^1.1.6, slide@~1.1.3, slide@~1.1.6:
7691 version "1.1.6"
7692 resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
7693 integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=
7694
7695smart-buffer@4.0.2:
7696 version "4.0.2"
7697 resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.2.tgz#5207858c3815cc69110703c6b94e46c15634395d"
7698 integrity sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==
7699
7700smtp-connection@2.3.1: 6552smtp-connection@2.3.1:
7701 version "2.3.1" 6553 version "2.3.1"
7702 resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-2.3.1.tgz#d169c8f1c9a73854134cdabe6fb818237dfc4fba" 6554 resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-2.3.1.tgz#d169c8f1c9a73854134cdabe6fb818237dfc4fba"
@@ -7836,35 +6688,6 @@ socket.io@^2.2.0:
7836 socket.io-client "2.2.0" 6688 socket.io-client "2.2.0"
7837 socket.io-parser "~3.3.0" 6689 socket.io-parser "~3.3.0"
7838 6690
7839socks-proxy-agent@^4.0.0:
7840 version "4.0.2"
7841 resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386"
7842 integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==
7843 dependencies:
7844 agent-base "~4.2.1"
7845 socks "~2.3.2"
7846
7847socks@~2.3.2:
7848 version "2.3.2"
7849 resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.2.tgz#ade388e9e6d87fdb11649c15746c578922a5883e"
7850 integrity sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ==
7851 dependencies:
7852 ip "^1.1.5"
7853 smart-buffer "4.0.2"
7854
7855sorted-object@~2.0.1:
7856 version "2.0.1"
7857 resolved "https://registry.yarnpkg.com/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc"
7858 integrity sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw=
7859
7860sorted-union-stream@~2.1.3:
7861 version "2.1.3"
7862 resolved "https://registry.yarnpkg.com/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz#c7794c7e077880052ff71a8d4a2dbb4a9a638ac7"
7863 integrity sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=
7864 dependencies:
7865 from2 "^1.3.0"
7866 stream-iterate "^1.1.0"
7867
7868source-map-resolve@^0.5.0: 6691source-map-resolve@^0.5.0:
7869 version "0.5.2" 6692 version "0.5.2"
7870 resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" 6693 resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
@@ -7877,9 +6700,9 @@ source-map-resolve@^0.5.0:
7877 urix "^0.1.0" 6700 urix "^0.1.0"
7878 6701
7879source-map-support@^0.5.0, source-map-support@^0.5.6: 6702source-map-support@^0.5.0, source-map-support@^0.5.6:
7880 version "0.5.11" 6703 version "0.5.12"
7881 resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.11.tgz#efac2ce0800355d026326a0ca23e162aeac9a4e2" 6704 resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599"
7882 integrity sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ== 6705 integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==
7883 dependencies: 6706 dependencies:
7884 buffer-from "^1.0.0" 6707 buffer-from "^1.0.0"
7885 source-map "^0.6.0" 6708 source-map "^0.6.0"
@@ -7926,20 +6749,15 @@ spdx-expression-parse@^3.0.0:
7926 spdx-license-ids "^3.0.0" 6749 spdx-license-ids "^3.0.0"
7927 6750
7928spdx-license-ids@^3.0.0: 6751spdx-license-ids@^3.0.0:
7929 version "3.0.3" 6752 version "3.0.4"
7930 resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e" 6753 resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1"
7931 integrity sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g== 6754 integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==
7932 6755
7933speedometer@^1.0.0: 6756speedometer@^1.0.0:
7934 version "1.1.0" 6757 version "1.1.0"
7935 resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.1.0.tgz#a30b13abda45687a1a76977012c060f2ac8a7934" 6758 resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.1.0.tgz#a30b13abda45687a1a76977012c060f2ac8a7934"
7936 integrity sha512-z/wAiTESw2XVPssY2XRcme4niTc4S5FkkJ4gknudtVoc33Zil8TdTxHy5torRcgqMqksJV2Yz8HQcvtbsnw0mQ== 6759 integrity sha512-z/wAiTESw2XVPssY2XRcme4niTc4S5FkkJ4gknudtVoc33Zil8TdTxHy5torRcgqMqksJV2Yz8HQcvtbsnw0mQ==
7937 6760
7938split-on-first@^1.0.0:
7939 version "1.0.0"
7940 resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.0.0.tgz#648af4ce9a28fbcaadd43274455f298b55025fc6"
7941 integrity sha512-mjA57TQtdWztVZ9THAjGNpgbuIrNfsNrGa5IyK94NoPaT4N14M+GI4jD7t4arLjFkYRQWdETC5RxFzLWouoB3A==
7942
7943split-string@^3.0.1, split-string@^3.0.2: 6761split-string@^3.0.1, split-string@^3.0.2:
7944 version "3.1.0" 6762 version "3.1.0"
7945 resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" 6763 resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
@@ -7993,13 +6811,6 @@ sshpk@^1.7.0:
7993 safer-buffer "^2.0.2" 6811 safer-buffer "^2.0.2"
7994 tweetnacl "~0.14.0" 6812 tweetnacl "~0.14.0"
7995 6813
7996ssri@^6.0.0, ssri@^6.0.1:
7997 version "6.0.1"
7998 resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
7999 integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==
8000 dependencies:
8001 figgy-pudding "^3.5.1"
8002
8003stack-trace@0.0.x: 6814stack-trace@0.0.x:
8004 version "0.0.10" 6815 version "0.0.10"
8005 resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" 6816 resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
@@ -8023,7 +6834,7 @@ static-extend@^0.1.1:
8023 define-property "^0.2.5" 6834 define-property "^0.2.5"
8024 object-copy "^0.1.0" 6835 object-copy "^0.1.0"
8025 6836
8026statuses@1, "statuses@>= 1.4.0 < 2": 6837statuses@1, "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
8027 version "1.5.0" 6838 version "1.5.0"
8028 resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 6839 resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
8029 integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 6840 integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
@@ -8038,27 +6849,6 @@ statuses@~1.2.1:
8038 resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.2.1.tgz#dded45cc18256d51ed40aec142489d5c61026d28" 6849 resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.2.1.tgz#dded45cc18256d51ed40aec142489d5c61026d28"
8039 integrity sha1-3e1FzBglbVHtQK7BQkidXGECbSg= 6850 integrity sha1-3e1FzBglbVHtQK7BQkidXGECbSg=
8040 6851
8041statuses@~1.4.0:
8042 version "1.4.0"
8043 resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
8044 integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
8045
8046stream-each@^1.1.0:
8047 version "1.2.3"
8048 resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
8049 integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==
8050 dependencies:
8051 end-of-stream "^1.1.0"
8052 stream-shift "^1.0.0"
8053
8054stream-iterate@^1.1.0:
8055 version "1.2.0"
8056 resolved "https://registry.yarnpkg.com/stream-iterate/-/stream-iterate-1.2.0.tgz#2bd7c77296c1702a46488b8ad41f79865eecd4e1"
8057 integrity sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=
8058 dependencies:
8059 readable-stream "^2.1.5"
8060 stream-shift "^1.0.0"
8061
8062stream-shift@^1.0.0: 6852stream-shift@^1.0.0:
8063 version "1.0.0" 6853 version "1.0.0"
8064 resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" 6854 resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
@@ -8109,11 +6899,6 @@ streamsearch@0.1.2:
8109 resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" 6899 resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
8110 integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= 6900 integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
8111 6901
8112strict-uri-encode@^2.0.0:
8113 version "2.0.0"
8114 resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
8115 integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
8116
8117string-argv@^0.0.2: 6902string-argv@^0.0.2:
8118 version "0.0.2" 6903 version "0.0.2"
8119 resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.0.2.tgz#dac30408690c21f3c3630a3ff3a05877bdcbd736" 6904 resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.0.2.tgz#dac30408690c21f3c3630a3ff3a05877bdcbd736"
@@ -8136,6 +6921,15 @@ string-width@^1.0.1:
8136 is-fullwidth-code-point "^2.0.0" 6921 is-fullwidth-code-point "^2.0.0"
8137 strip-ansi "^4.0.0" 6922 strip-ansi "^4.0.0"
8138 6923
6924string-width@^3.0.0, string-width@^3.1.0:
6925 version "3.1.0"
6926 resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
6927 integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
6928 dependencies:
6929 emoji-regex "^7.0.1"
6930 is-fullwidth-code-point "^2.0.0"
6931 strip-ansi "^5.1.0"
6932
8139string2compact@^1.1.1, string2compact@^1.2.5: 6933string2compact@^1.1.1, string2compact@^1.2.5:
8140 version "1.3.0" 6934 version "1.3.0"
8141 resolved "https://registry.yarnpkg.com/string2compact/-/string2compact-1.3.0.tgz#22d946127b082d1203c51316af60117a337423c3" 6935 resolved "https://registry.yarnpkg.com/string2compact/-/string2compact-1.3.0.tgz#22d946127b082d1203c51316af60117a337423c3"
@@ -8172,11 +6966,6 @@ stringify-object@^3.2.2:
8172 is-obj "^1.0.1" 6966 is-obj "^1.0.1"
8173 is-regexp "^1.0.0" 6967 is-regexp "^1.0.0"
8174 6968
8175stringify-package@^1.0.0:
8176 version "1.0.0"
8177 resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.0.tgz#e02828089333d7d45cd8c287c30aa9a13375081b"
8178 integrity sha512-JIQqiWmLiEozOC0b0BtxZ/AOUtdUZHCBPgqIZ2kSJJqGwgb9neo44XdTHUC4HZSGqi03hOeB7W/E8rAlKnGe9g==
8179
8180strip-ansi@^3.0.0, strip-ansi@^3.0.1: 6969strip-ansi@^3.0.0, strip-ansi@^3.0.1:
8181 version "3.0.1" 6970 version "3.0.1"
8182 resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 6971 resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
@@ -8191,6 +6980,13 @@ strip-ansi@^4.0.0:
8191 dependencies: 6980 dependencies:
8192 ansi-regex "^3.0.0" 6981 ansi-regex "^3.0.0"
8193 6982
6983strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
6984 version "5.2.0"
6985 resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
6986 integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
6987 dependencies:
6988 ansi-regex "^4.1.0"
6989
8194strip-eof@^1.0.0: 6990strip-eof@^1.0.0:
8195 version "1.0.0" 6991 version "1.0.0"
8196 resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" 6992 resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
@@ -8206,15 +7002,6 @@ strip-json-comments@~1.0.1:
8206 resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" 7002 resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"
8207 integrity sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E= 7003 integrity sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=
8208 7004
8209summon-install@^0.4.3:
8210 version "0.4.6"
8211 resolved "https://registry.yarnpkg.com/summon-install/-/summon-install-0.4.6.tgz#25673446e8b92f8bc0afabc464aa7b73fe946bd5"
8212 integrity sha512-xLiRo8z2srFItquk4VXGfC6AsELPmFCYev5pipARHVCikrgCBdjHMxs2ZGfVcsOOKwTgEL6bVFutf5yF43GBZw==
8213 dependencies:
8214 descrevit "^0.1.1"
8215 dot-json "^1.0.3"
8216 npm "*"
8217
8218superagent@^3.8.3: 7005superagent@^3.8.3:
8219 version "3.8.3" 7006 version "3.8.3"
8220 resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" 7007 resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128"
@@ -8304,10 +7091,10 @@ symbol-observable@^1.1.0:
8304 resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" 7091 resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
8305 integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== 7092 integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
8306 7093
8307synchronous-promise@^2.0.5: 7094synchronous-promise@^2.0.6:
8308 version "2.0.7" 7095 version "2.0.9"
8309 resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.7.tgz#3574b3d2fae86b145356a4b89103e1577f646fe3" 7096 resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.9.tgz#b83db98e9e7ae826bf9c8261fd8ac859126c780a"
8310 integrity sha512-16GbgwTmFMYFyQMLvtQjvNWh30dsFe1cAW5Fg1wm5+dg84L9Pe36mftsIRU95/W2YsISxsz/xq4VB23sqpgb/A== 7097 integrity sha512-LO95GIW16x69LuND1nuuwM4pjgFGupg7pZ/4lU86AmchPKrhk0o2tpMU2unXRrqo81iAFe1YJ0nAGEVwsrZAgg==
8311 7098
8312table@^3.7.8: 7099table@^3.7.8:
8313 version "3.8.3" 7100 version "3.8.3"
@@ -8344,27 +7131,18 @@ tar-stream@^1.1.2:
8344 to-buffer "^1.1.1" 7131 to-buffer "^1.1.1"
8345 xtend "^4.0.0" 7132 xtend "^4.0.0"
8346 7133
8347tar@^2.0.0:
8348 version "2.2.1"
8349 resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
8350 integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=
8351 dependencies:
8352 block-stream "*"
8353 fstream "^1.0.2"
8354 inherits "2"
8355
8356tar@^4, tar@^4.4.8: 7134tar@^4, tar@^4.4.8:
8357 version "4.4.8" 7135 version "4.4.10"
8358 resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" 7136 resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1"
8359 integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== 7137 integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==
8360 dependencies: 7138 dependencies:
8361 chownr "^1.1.1" 7139 chownr "^1.1.1"
8362 fs-minipass "^1.2.5" 7140 fs-minipass "^1.2.5"
8363 minipass "^2.3.4" 7141 minipass "^2.3.5"
8364 minizlib "^1.1.1" 7142 minizlib "^1.2.1"
8365 mkdirp "^0.5.0" 7143 mkdirp "^0.5.0"
8366 safe-buffer "^5.1.2" 7144 safe-buffer "^5.1.2"
8367 yallist "^3.0.2" 7145 yallist "^3.0.3"
8368 7146
8369term-size@^1.2.0: 7147term-size@^1.2.0:
8370 version "1.2.0" 7148 version "1.2.0"
@@ -8404,7 +7182,7 @@ through2@^1.0.0:
8404 readable-stream ">=1.1.13-1 <1.2.0-0" 7182 readable-stream ">=1.1.13-1 <1.2.0-0"
8405 xtend ">=4.0.0 <4.1.0-0" 7183 xtend ">=4.0.0 <4.1.0-0"
8406 7184
8407through2@^2.0.0, through2@^2.0.3: 7185through2@^2.0.3:
8408 version "2.0.5" 7186 version "2.0.5"
8409 resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" 7187 resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
8410 integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== 7188 integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
@@ -8412,7 +7190,7 @@ through2@^2.0.0, through2@^2.0.3:
8412 readable-stream "~2.3.6" 7190 readable-stream "~2.3.6"
8413 xtend "~4.0.1" 7191 xtend "~4.0.1"
8414 7192
8415through@2, "through@>=2.2.7 <3", through@^2.3.6: 7193through@2, through@^2.3.6:
8416 version "2.3.8" 7194 version "2.3.8"
8417 resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 7195 resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
8418 integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= 7196 integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
@@ -8435,11 +7213,6 @@ timers-ext@^0.1.5:
8435 es5-ext "~0.10.46" 7213 es5-ext "~0.10.46"
8436 next-tick "1" 7214 next-tick "1"
8437 7215
8438tiny-relative-date@^1.3.0:
8439 version "1.3.0"
8440 resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07"
8441 integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==
8442
8443tmp@0.0.x: 7216tmp@0.0.x:
8444 version "0.0.33" 7217 version "0.0.33"
8445 resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" 7218 resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@@ -8498,6 +7271,11 @@ to-utf-8@^1.2.0:
8498 peek-stream "^1.1.1" 7271 peek-stream "^1.1.1"
8499 stream-splicer "^1.3.1" 7272 stream-splicer "^1.3.1"
8500 7273
7274toidentifier@1.0.0:
7275 version "1.0.0"
7276 resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
7277 integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
7278
8501toposort-class@^1.0.1: 7279toposort-class@^1.0.1:
8502 version "1.0.1" 7280 version "1.0.1"
8503 resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988" 7281 resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988"
@@ -8553,13 +7331,13 @@ triple-beam@^1.2.0, triple-beam@^1.3.0:
8553 resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" 7331 resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
8554 integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== 7332 integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
8555 7333
8556ts-node@8.0.3: 7334ts-node@8.2.0:
8557 version "8.0.3" 7335 version "8.2.0"
8558 resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.0.3.tgz#aa60b836a24dafd8bf21b54766841a232fdbc641" 7336 resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.2.0.tgz#4a89754b00560bb24cd54526e1685fa38c45f240"
8559 integrity sha512-2qayBA4vdtVRuDo11DEFSsD/SFsBXQBRZZhbRGSIkmYmVkWjULn/GGMdG10KVqkaGndljfaTD8dKjWgcejO8YA== 7337 integrity sha512-m8XQwUurkbYqXrKqr3WHCW310utRNvV5OnRVeISeea7LoCWVcdfeB/Ntl8JYWFh+WRoUAdBgESrzKochQt7sMw==
8560 dependencies: 7338 dependencies:
8561 arg "^4.1.0" 7339 arg "^4.1.0"
8562 diff "^3.1.0" 7340 diff "^4.0.1"
8563 make-error "^1.1.1" 7341 make-error "^1.1.1"
8564 source-map-support "^0.5.6" 7342 source-map-support "^0.5.6"
8565 yn "^3.0.0" 7343 yn "^3.0.0"
@@ -8591,17 +7369,17 @@ tslint-eslint-rules@^5.3.1:
8591 tsutils "^3.0.0" 7369 tsutils "^3.0.0"
8592 7370
8593tslint@^5.7.0: 7371tslint@^5.7.0:
8594 version "5.15.0" 7372 version "5.17.0"
8595 resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.15.0.tgz#6ffb180986d63afa1e531feb2a134dbf961e27d3" 7373 resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.17.0.tgz#f9f0ce2011d8e90debaa6e9b4975f24cd16852b8"
8596 integrity sha512-6bIEujKR21/3nyeoX2uBnE8s+tMXCQXhqMmaIPJpHmXJoBJPTLcI7/VHRtUwMhnLVdwLqqY3zmd8Dxqa5CVdJA== 7374 integrity sha512-pflx87WfVoYepTet3xLfDOLDm9Jqi61UXIKePOuca0qoAZyrGWonDG9VTbji58Fy+8gciUn8Bt7y69+KEVjc/w==
8597 dependencies: 7375 dependencies:
8598 babel-code-frame "^6.22.0" 7376 "@babel/code-frame" "^7.0.0"
8599 builtin-modules "^1.1.1" 7377 builtin-modules "^1.1.1"
8600 chalk "^2.3.0" 7378 chalk "^2.3.0"
8601 commander "^2.12.1" 7379 commander "^2.12.1"
8602 diff "^3.2.0" 7380 diff "^3.2.0"
8603 glob "^7.1.1" 7381 glob "^7.1.1"
8604 js-yaml "^3.13.0" 7382 js-yaml "^3.13.1"
8605 minimatch "^3.0.4" 7383 minimatch "^3.0.4"
8606 mkdirp "^0.5.1" 7384 mkdirp "^0.5.1"
8607 resolve "^1.3.2" 7385 resolve "^1.3.2"
@@ -8617,9 +7395,9 @@ tsutils@^2.29.0:
8617 tslib "^1.8.1" 7395 tslib "^1.8.1"
8618 7396
8619tsutils@^3.0.0: 7397tsutils@^3.0.0:
8620 version "3.9.1" 7398 version "3.14.0"
8621 resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.9.1.tgz#2a40dc742943c71eca6d5c1994fcf999956be387" 7399 resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.14.0.tgz#bf8d5a7bae5369331fa0f2b0a5a10bd7f7396c77"
8622 integrity sha512-hrxVtLtPqQr//p8/msPT1X1UYXUjizqSit5d9AQ5k38TcV38NyecL5xODNxa73cLe/5sdiJ+w1FqzDhRBA/anA== 7400 integrity sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw==
8623 dependencies: 7401 dependencies:
8624 tslib "^1.8.1" 7402 tslib "^1.8.1"
8625 7403
@@ -8630,10 +7408,10 @@ tunnel-agent@^0.6.0:
8630 dependencies: 7408 dependencies:
8631 safe-buffer "^5.0.1" 7409 safe-buffer "^5.0.1"
8632 7410
8633tv4@~1.2.7: 7411tv4@^1.3.0:
8634 version "1.2.7" 7412 version "1.3.0"
8635 resolved "https://registry.yarnpkg.com/tv4/-/tv4-1.2.7.tgz#bd29389afc73ade49ae5f48142b5d544bf68d120" 7413 resolved "https://registry.yarnpkg.com/tv4/-/tv4-1.3.0.tgz#d020c846fadd50c855abb25ebaecc68fc10f7963"
8636 integrity sha1-vSk4mvxzreSa5fSBQrXVRL9o0SA= 7414 integrity sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM=
8637 7415
8638tweetnacl@^0.14.3, tweetnacl@~0.14.0: 7416tweetnacl@^0.14.3, tweetnacl@~0.14.0:
8639 version "0.14.5" 7417 version "0.14.5"
@@ -8657,6 +7435,16 @@ type-detect@^4.0.0, type-detect@^4.0.5:
8657 resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 7435 resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
8658 integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== 7436 integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
8659 7437
7438type-fest@^0.3.0:
7439 version "0.3.1"
7440 resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"
7441 integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==
7442
7443type-fest@^0.4.1:
7444 version "0.4.1"
7445 resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8"
7446 integrity sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==
7447
8660type-is@1.6.15: 7448type-is@1.6.15:
8661 version "1.6.15" 7449 version "1.6.15"
8662 resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" 7450 resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
@@ -8665,13 +7453,13 @@ type-is@1.6.15:
8665 media-typer "0.3.0" 7453 media-typer "0.3.0"
8666 mime-types "~2.1.15" 7454 mime-types "~2.1.15"
8667 7455
8668type-is@^1.6.4, type-is@~1.6.16, type-is@~1.6.6: 7456type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18, type-is@~1.6.6:
8669 version "1.6.16" 7457 version "1.6.18"
8670 resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" 7458 resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
8671 integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== 7459 integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
8672 dependencies: 7460 dependencies:
8673 media-typer "0.3.0" 7461 media-typer "0.3.0"
8674 mime-types "~2.1.18" 7462 mime-types "~2.1.24"
8675 7463
8676typedarray-to-buffer@^3.0.0: 7464typedarray-to-buffer@^3.0.0:
8677 version "3.1.5" 7465 version "3.1.5"
@@ -8686,14 +7474,9 @@ typedarray@^0.0.6:
8686 integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= 7474 integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
8687 7475
8688typescript@^3.4.3: 7476typescript@^3.4.3:
8689 version "3.4.3" 7477 version "3.5.1"
8690 resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.3.tgz#0eb320e4ace9b10eadf5bc6103286b0f8b7c224f" 7478 resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.1.tgz#ba72a6a600b2158139c5dd8850f700e231464202"
8691 integrity sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ== 7479 integrity sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw==
8692
8693uid-number@0.0.6:
8694 version "0.0.6"
8695 resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
8696 integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=
8697 7480
8698uint64be@^2.0.2: 7481uint64be@^2.0.2:
8699 version "2.0.2" 7482 version "2.0.2"
@@ -8707,11 +7490,6 @@ ultron@1.0.x:
8707 resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" 7490 resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"
8708 integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po= 7491 integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=
8709 7492
8710umask@^1.1.0, umask@~1.1.0:
8711 version "1.1.0"
8712 resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d"
8713 integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=
8714
8715undefsafe@^2.0.2: 7493undefsafe@^2.0.2:
8716 version "2.0.2" 7494 version "2.0.2"
8717 resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76" 7495 resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76"
@@ -8719,18 +7497,6 @@ undefsafe@^2.0.2:
8719 dependencies: 7497 dependencies:
8720 debug "^2.2.0" 7498 debug "^2.2.0"
8721 7499
8722underscore-keypath@~0.0.22:
8723 version "0.0.22"
8724 resolved "https://registry.yarnpkg.com/underscore-keypath/-/underscore-keypath-0.0.22.tgz#48a528392bb6efc424be1caa56da4b5faccf264d"
8725 integrity sha1-SKUoOSu278QkvhyqVtpLX6zPJk0=
8726 dependencies:
8727 underscore "*"
8728
8729underscore@*:
8730 version "1.9.1"
8731 resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961"
8732 integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==
8733
8734union-value@^1.0.0: 7500union-value@^1.0.0:
8735 version "1.0.0" 7501 version "1.0.0"
8736 resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" 7502 resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
@@ -8746,20 +7512,6 @@ uniq@^1.0.1:
8746 resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" 7512 resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
8747 integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= 7513 integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=
8748 7514
8749unique-filename@^1.1.1:
8750 version "1.1.1"
8751 resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
8752 integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==
8753 dependencies:
8754 unique-slug "^2.0.0"
8755
8756unique-slug@^2.0.0:
8757 version "2.0.1"
8758 resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6"
8759 integrity sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==
8760 dependencies:
8761 imurmurhash "^0.1.4"
8762
8763unique-string@^1.0.0: 7515unique-string@^1.0.0:
8764 version "1.0.0" 7516 version "1.0.0"
8765 resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" 7517 resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
@@ -8800,7 +7552,7 @@ upath@^1.1.1:
8800 resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" 7552 resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068"
8801 integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== 7553 integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==
8802 7554
8803update-notifier@^2.3.0, update-notifier@^2.5.0: 7555update-notifier@^2.5.0:
8804 version "2.5.0" 7556 version "2.5.0"
8805 resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" 7557 resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6"
8806 integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw== 7558 integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==
@@ -8892,11 +7644,6 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1:
8892 resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 7644 resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
8893 integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 7645 integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
8894 7646
8895util-extend@^1.0.1:
8896 version "1.0.3"
8897 resolved "https://registry.yarnpkg.com/util-extend/-/util-extend-1.0.3.tgz#a7c216d267545169637b3b6edc6ca9119e2ff93f"
8898 integrity sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=
8899
8900util.promisify@^1.0.0: 7647util.promisify@^1.0.0:
8901 version "1.0.0" 7648 version "1.0.0"
8902 resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" 7649 resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030"
@@ -8947,7 +7694,7 @@ uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2:
8947 resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" 7694 resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
8948 integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== 7695 integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
8949 7696
8950validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: 7697validate-npm-package-license@^3.0.1:
8951 version "3.0.4" 7698 version "3.0.4"
8952 resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" 7699 resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
8953 integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== 7700 integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
@@ -8955,18 +7702,16 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4:
8955 spdx-correct "^3.0.0" 7702 spdx-correct "^3.0.0"
8956 spdx-expression-parse "^3.0.0" 7703 spdx-expression-parse "^3.0.0"
8957 7704
8958validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0: 7705validator@^10.0.0, validator@^10.11.0, validator@^10.4.0:
8959 version "3.0.0"
8960 resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e"
8961 integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34=
8962 dependencies:
8963 builtins "^1.0.3"
8964
8965validator@^10.0.0, validator@^10.11.0, validator@^10.2.0, validator@^10.4.0:
8966 version "10.11.0" 7706 version "10.11.0"
8967 resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" 7707 resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228"
8968 integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== 7708 integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==
8969 7709
7710validator@^11.0.0:
7711 version "11.0.0"
7712 resolved "https://registry.yarnpkg.com/validator/-/validator-11.0.0.tgz#fb10128bfb1fd14ce4ed36b79fc94289eae70667"
7713 integrity sha512-+wnGLYqaKV2++nUv60uGzUJyJQwYVOin6pn1tgEiFCeCQO60yeu3Og9/yPccbBX574kxIcEJicogkzx6s6eyag==
7714
8970vary@^1, vary@~1.1.2: 7715vary@^1, vary@~1.1.2:
8971 version "1.1.2" 7716 version "1.1.2"
8972 resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 7717 resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
@@ -9000,13 +7745,6 @@ videostream@^2.5.1:
9000 pump "^3.0.0" 7745 pump "^3.0.0"
9001 range-slice-stream "^2.0.0" 7746 range-slice-stream "^2.0.0"
9002 7747
9003wcwidth@^1.0.0:
9004 version "1.0.1"
9005 resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
9006 integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
9007 dependencies:
9008 defaults "^1.0.3"
9009
9010webfinger.js@^2.6.6: 7748webfinger.js@^2.6.6:
9011 version "2.7.0" 7749 version "2.7.0"
9012 resolved "https://registry.yarnpkg.com/webfinger.js/-/webfinger.js-2.7.0.tgz#403354a14a65aeeba64c1408c18a387487cea106" 7750 resolved "https://registry.yarnpkg.com/webfinger.js/-/webfinger.js-2.7.0.tgz#403354a14a65aeeba64c1408c18a387487cea106"
@@ -9070,7 +7808,7 @@ which-pm-runs@^1.0.0:
9070 resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" 7808 resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
9071 integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= 7809 integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=
9072 7810
9073which@1, which@1.3.1, which@^1.1.1, which@^1.2.10, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1: 7811which@1.3.1, which@^1.1.1, which@^1.2.10, which@^1.2.9, which@^1.3.1:
9074 version "1.3.1" 7812 version "1.3.1"
9075 resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 7813 resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
9076 integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 7814 integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -9144,13 +7882,6 @@ wordwrap@~1.0.0:
9144 resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 7882 resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
9145 integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= 7883 integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
9146 7884
9147worker-farm@^1.6.0:
9148 version "1.6.0"
9149 resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0"
9150 integrity sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==
9151 dependencies:
9152 errno "~0.1.7"
9153
9154wrap-ansi@^2.0.0: 7885wrap-ansi@^2.0.0:
9155 version "2.1.0" 7886 version "2.1.0"
9156 resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" 7887 resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
@@ -9167,15 +7898,24 @@ wrap-ansi@^3.0.1:
9167 string-width "^2.1.1" 7898 string-width "^2.1.1"
9168 strip-ansi "^4.0.0" 7899 strip-ansi "^4.0.0"
9169 7900
7901wrap-ansi@^5.1.0:
7902 version "5.1.0"
7903 resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
7904 integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
7905 dependencies:
7906 ansi-styles "^3.2.0"
7907 string-width "^3.0.0"
7908 strip-ansi "^5.0.0"
7909
9170wrappy@1: 7910wrappy@1:
9171 version "1.0.2" 7911 version "1.0.2"
9172 resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 7912 resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
9173 integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 7913 integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
9174 7914
9175write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: 7915write-file-atomic@^2.0.0:
9176 version "2.4.2" 7916 version "2.4.3"
9177 resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.2.tgz#a7181706dfba17855d221140a9c06e15fcdd87b9" 7917 resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481"
9178 integrity sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g== 7918 integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==
9179 dependencies: 7919 dependencies:
9180 graceful-fs "^4.1.11" 7920 graceful-fs "^4.1.11"
9181 imurmurhash "^0.1.4" 7921 imurmurhash "^0.1.4"
@@ -9203,6 +7943,13 @@ ws@^6.0.0:
9203 dependencies: 7943 dependencies:
9204 async-limiter "~1.0.0" 7944 async-limiter "~1.0.0"
9205 7945
7946ws@^7.0.0:
7947 version "7.0.0"
7948 resolved "https://registry.yarnpkg.com/ws/-/ws-7.0.0.tgz#79351cbc3f784b3c20d0821baf4b4ff809ffbf51"
7949 integrity sha512-cknCal4k0EAOrh1SHHPPWWh4qm93g1IuGGGwBjWkXmCG7LsDtL8w9w+YVfaF+KSVwiHQKDIMsSLBVftKf9d1pg==
7950 dependencies:
7951 async-limiter "^1.0.0"
7952
9206ws@~6.1.0: 7953ws@~6.1.0:
9207 version "6.1.4" 7954 version "6.1.4"
9208 resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" 7955 resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
@@ -9231,9 +7978,9 @@ xhr2@^0.1.4:
9231 integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= 7978 integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8=
9232 7979
9233xliff@^4.0.0: 7980xliff@^4.0.0:
9234 version "4.3.0" 7981 version "4.3.1"
9235 resolved "https://registry.yarnpkg.com/xliff/-/xliff-4.3.0.tgz#de08098a63ead8afde0bae83f059b8cbf3badaf1" 7982 resolved "https://registry.yarnpkg.com/xliff/-/xliff-4.3.1.tgz#ae82d1c6283014aa7506c9957bcb3f95ed1ce505"
9236 integrity sha512-YDGHMdgmzDOjDm9ys+CdesxC9NBaxOcARR8fdJKHS8qY+XbW6g0BAaRBj0ssC1H9s5lrY0m2uqLCu0HB58K2ag== 7983 integrity sha512-SERrOPuKZ/5XyEiv+cXgIjidQq4vp6HYS0yBS2GwC1TDJiREFaUIin3qg4OBlD6jdFWdPOMwkXGackAvgZ6+LQ==
9237 dependencies: 7984 dependencies:
9238 xml-js "1.6.11" 7985 xml-js "1.6.11"
9239 7986
@@ -9287,11 +8034,6 @@ xmlhttprequest-ssl@~1.5.4:
9287 resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 8034 resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
9288 integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= 8035 integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
9289 8036
9290y18n@^3.2.1:
9291 version "3.2.1"
9292 resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
9293 integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
9294
9295"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: 8037"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0:
9296 version "4.0.0" 8038 version "4.0.0"
9297 resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" 8039 resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
@@ -9302,12 +8044,20 @@ yallist@^2.1.2:
9302 resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" 8044 resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
9303 integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= 8045 integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
9304 8046
9305yallist@^3.0.0, yallist@^3.0.2: 8047yallist@^3.0.0, yallist@^3.0.3:
9306 version "3.0.3" 8048 version "3.0.3"
9307 resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" 8049 resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
9308 integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== 8050 integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
9309 8051
9310yargs-parser@11.1.1, yargs-parser@^11.1.1: 8052yargs-parser@13.0.0:
8053 version "13.0.0"
8054 resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b"
8055 integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==
8056 dependencies:
8057 camelcase "^5.0.0"
8058 decamelize "^1.2.0"
8059
8060yargs-parser@^11.1.1:
9311 version "11.1.1" 8061 version "11.1.1"
9312 resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" 8062 resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4"
9313 integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== 8063 integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==
@@ -9315,6 +8065,14 @@ yargs-parser@11.1.1, yargs-parser@^11.1.1:
9315 camelcase "^5.0.0" 8065 camelcase "^5.0.0"
9316 decamelize "^1.2.0" 8066 decamelize "^1.2.0"
9317 8067
8068yargs-parser@^13.0.0, yargs-parser@^13.1.0:
8069 version "13.1.0"
8070 resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.0.tgz#7016b6dd03e28e1418a510e258be4bff5a31138f"
8071 integrity sha512-Yq+32PrijHRri0vVKQEm+ys8mbqWjLiwQkMFNXEENutzLPP0bE4Lcd4iA3OQY5HF+GD3xXxf0MEHb8E4/SA3AA==
8072 dependencies:
8073 camelcase "^5.0.0"
8074 decamelize "^1.2.0"
8075
9318yargs-parser@^8.0.0: 8076yargs-parser@^8.0.0:
9319 version "8.1.0" 8077 version "8.1.0"
9320 resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" 8078 resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950"
@@ -9322,13 +8080,6 @@ yargs-parser@^8.0.0:
9322 dependencies: 8080 dependencies:
9323 camelcase "^4.1.0" 8081 camelcase "^4.1.0"
9324 8082
9325yargs-parser@^9.0.2:
9326 version "9.0.2"
9327 resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077"
9328 integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=
9329 dependencies:
9330 camelcase "^4.1.0"
9331
9332yargs-unparser@1.5.0: 8083yargs-unparser@1.5.0:
9333 version "1.5.0" 8084 version "1.5.0"
9334 resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d" 8085 resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d"
@@ -9338,7 +8089,24 @@ yargs-unparser@1.5.0:
9338 lodash "^4.17.11" 8089 lodash "^4.17.11"
9339 yargs "^12.0.5" 8090 yargs "^12.0.5"
9340 8091
9341yargs@12.0.5, yargs@^12.0.1, yargs@^12.0.5: 8092yargs@13.2.2:
8093 version "13.2.2"
8094 resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993"
8095 integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==
8096 dependencies:
8097 cliui "^4.0.0"
8098 find-up "^3.0.0"
8099 get-caller-file "^2.0.1"
8100 os-locale "^3.1.0"
8101 require-directory "^2.1.1"
8102 require-main-filename "^2.0.0"
8103 set-blocking "^2.0.0"
8104 string-width "^3.0.0"
8105 which-module "^2.0.0"
8106 y18n "^4.0.0"
8107 yargs-parser "^13.0.0"
8108
8109yargs@^12.0.1, yargs@^12.0.5:
9342 version "12.0.5" 8110 version "12.0.5"
9343 resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" 8111 resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
9344 integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== 8112 integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
@@ -9356,23 +8124,22 @@ yargs@12.0.5, yargs@^12.0.1, yargs@^12.0.5:
9356 y18n "^3.2.1 || ^4.0.0" 8124 y18n "^3.2.1 || ^4.0.0"
9357 yargs-parser "^11.1.1" 8125 yargs-parser "^11.1.1"
9358 8126
9359yargs@^11.0.0: 8127yargs@^13.2.2:
9360 version "11.1.0" 8128 version "13.2.4"
9361 resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" 8129 resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83"
9362 integrity sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A== 8130 integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==
9363 dependencies: 8131 dependencies:
9364 cliui "^4.0.0" 8132 cliui "^5.0.0"
9365 decamelize "^1.1.1" 8133 find-up "^3.0.0"
9366 find-up "^2.1.0" 8134 get-caller-file "^2.0.1"
9367 get-caller-file "^1.0.1" 8135 os-locale "^3.1.0"
9368 os-locale "^2.0.0"
9369 require-directory "^2.1.1" 8136 require-directory "^2.1.1"
9370 require-main-filename "^1.0.1" 8137 require-main-filename "^2.0.0"
9371 set-blocking "^2.0.0" 8138 set-blocking "^2.0.0"
9372 string-width "^2.0.0" 8139 string-width "^3.0.0"
9373 which-module "^2.0.0" 8140 which-module "^2.0.0"
9374 y18n "^3.2.1" 8141 y18n "^4.0.0"
9375 yargs-parser "^9.0.2" 8142 yargs-parser "^13.1.0"
9376 8143
9377yeast@0.1.2: 8144yeast@0.1.2:
9378 version "0.1.2" 8145 version "0.1.2"
@@ -9380,30 +8147,30 @@ yeast@0.1.2:
9380 integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= 8147 integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
9381 8148
9382yn@^3.0.0: 8149yn@^3.0.0:
9383 version "3.0.0" 8150 version "3.1.0"
9384 resolved "https://registry.yarnpkg.com/yn/-/yn-3.0.0.tgz#0073c6b56e92aed652fbdfd62431f2d6b9a7a091" 8151 resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.0.tgz#fcbe2db63610361afcc5eb9e0ac91e976d046114"
9385 integrity sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q== 8152 integrity sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==
9386 8153
9387youtube-dl@^1.12.2: 8154youtube-dl@^2.0.0:
9388 version "1.13.1" 8155 version "2.0.0"
9389 resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-1.13.1.tgz#2da47c0dad3c5391e2172b7811da46501b82edc4" 8156 resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-2.0.0.tgz#64f85beff21a5b0b5651437ea51d10effd3dad5a"
9390 integrity sha512-89mUKwOavaojNKQlyzW+A7Dph5G/oPYs6T/PTMcvgdRQ5E2+uDQgYPxWHQDMBhHOkxQaxvxQTiTPKQLdg0OI4w== 8157 integrity sha512-1R5bcnBMVqQIk85wqTJ8pxPq5UbzxZXJy4KSaf3N1dedZG4uAzq5zuoiHcNcsGle5JtoHNpTWDBjTDhHO0SipQ==
9391 dependencies: 8158 dependencies:
9392 hh-mm-ss "~1.2.0" 8159 hh-mm-ss "~1.2.0"
9393 mkdirp "~0.5.1" 8160 mkdirp "~0.5.1"
9394 request "~2.88.0" 8161 request "~2.88.0"
9395 streamify "~0.2.9" 8162 streamify "~0.2.9"
9396 8163
9397yup@^0.26.10: 8164yup@^0.27.0:
9398 version "0.26.10" 8165 version "0.27.0"
9399 resolved "https://registry.yarnpkg.com/yup/-/yup-0.26.10.tgz#3545839663289038faf25facfc07e11fd67c0cb1" 8166 resolved "https://registry.yarnpkg.com/yup/-/yup-0.27.0.tgz#f8cb198c8e7dd2124beddc2457571329096b06e7"
9400 integrity sha512-keuNEbNSnsOTOuGCt3UJW69jDE3O4P+UHAakO7vSeFMnjaitcmlbij/a3oNb9g1Y1KvSKH/7O1R2PQ4m4TRylw== 8167 integrity sha512-v1yFnE4+u9za42gG/b/081E7uNW9mUj3qtkmelLbW5YPROZzSH/KUUyJu9Wt8vxFJcT9otL/eZopS0YK1L5yPQ==
9401 dependencies: 8168 dependencies:
9402 "@babel/runtime" "7.0.0" 8169 "@babel/runtime" "^7.0.0"
9403 fn-name "~2.0.1" 8170 fn-name "~2.0.1"
9404 lodash "^4.17.10" 8171 lodash "^4.17.11"
9405 property-expr "^1.5.0" 8172 property-expr "^1.5.0"
9406 synchronous-promise "^2.0.5" 8173 synchronous-promise "^2.0.6"
9407 toposort "^2.0.2" 8174 toposort "^2.0.2"
9408 8175
9409z-schema@^3.24.2: 8176z-schema@^3.24.2: