diff options
334 files changed, 8777 insertions, 4762 deletions
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b3847b8d7..bbf06c87f 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,12 @@ Make sure that you have followed | |||
61 | [the steps](/support/doc/dependencies.md) | 59 | [the steps](/support/doc/dependencies.md) |
62 | to install the dependencies. | 60 | to install the dependencies. |
63 | 61 | ||
64 | Then clone the sources and install node modules: | 62 | Fork the github repository, |
63 | and 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/Chocobozzz/PeerTube |
67 | $ git remote add me git@github.com:YOUR_GITHUB_USERNAME/PeerTube.git | ||
68 | $ cd PeerTube | 68 | $ cd PeerTube |
69 | $ yarn install --pure-lockfile | 69 | $ yarn install --pure-lockfile |
70 | ``` | 70 | ``` |
@@ -73,6 +73,12 @@ Note that development is done on the `develop` branch. If you want to hack on | |||
73 | Peertube, you should switch to that branch. Also note that you have to repeat | 73 | Peertube, you should switch to that branch. Also note that you have to repeat |
74 | the `yarn install --pure-lockfile` command. | 74 | the `yarn install --pure-lockfile` command. |
75 | 75 | ||
76 | When you create a new branch you should also tell to use your repo for upload | ||
77 | not default one. To do just do: | ||
78 | ``` | ||
79 | $ git push --set-upstream me <your branch name> | ||
80 | ``` | ||
81 | |||
76 | Then, create a postgres database and user with the values set in the | 82 | Then, create a postgres database and user with the values set in the |
77 | `config/default.yaml` file. For instance, if you do not change the values | 83 | `config/default.yaml` file. For instance, if you do not change the values |
78 | there, the following commands would create a new database called `peertube_dev` | 84 | there, the following commands would create a new database called `peertube_dev` |
@@ -101,7 +107,7 @@ You can get a complete PeerTube development setup with Gitpod, a free one-click | |||
101 | 107 | ||
102 | ### Server side | 108 | ### Server side |
103 | 109 | ||
104 | You can find a documentation of the server code/architecture [here](/support/doc/development/server/code.md). | 110 | You can find a documentation of the server code/architecture [here](https://docs.joinpeertube.org/#/contribute-architecture?id=server-code). |
105 | 111 | ||
106 | To develop on the server-side: | 112 | To develop on the server-side: |
107 | 113 | ||
@@ -115,8 +121,8 @@ restart. | |||
115 | 121 | ||
116 | ### Client side | 122 | ### Client side |
117 | 123 | ||
118 | You can find a documentation of the server code/architecture | 124 | You can find a documentation of the client code/architecture |
119 | [here](/support/doc/development/client/code.md). | 125 | [here](https://docs.joinpeertube.org/#/contribute-architecture?id=client-code). |
120 | 126 | ||
121 | 127 | ||
122 | To develop on the client side: | 128 | To develop on the client side: |
@@ -193,11 +199,3 @@ $ npm run mocha -- --exit --require ts-node/register/type-check --bail server/te | |||
193 | 199 | ||
194 | Instance configurations are in `config/test-{1,2,3,4,5,6}.yaml`. | 200 | Instance configurations are in `config/test-{1,2,3,4,5,6}.yaml`. |
195 | Note that only instance 2 has transcoding enabled. | 201 | Note that only instance 2 has transcoding enabled. |
196 | |||
197 | ### Troubleshooting | ||
198 | |||
199 | Please check out the issues and [list of common errors](https://docs.joinpeertube.org/lang/en/devdocs/troubleshooting.html). | ||
200 | |||
201 | ### Tutorials | ||
202 | |||
203 | Please 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/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..cece65761 --- /dev/null +++ b/.github/FUNDING.yml | |||
@@ -0,0 +1 @@ | |||
custom: https://framasoft.org/en/#soutenir | |||
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 | ||
31 | before_script: | 31 | before_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 cf8833833..3a8bf716f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md | |||
@@ -344,8 +344,8 @@ and update your [.env](https://github.com/Chocobozzz/PeerTube/blob/develop/suppo | |||
344 | 344 | ||
345 | ### Maintenance | 345 | ### Maintenance |
346 | 346 | ||
347 | * Improve REST API documentation: https://docs.joinpeertube.org/api.html ([@rigelk](https://github.com/rigelk)) | 347 | * Improve REST API documentation ([@rigelk](https://github.com/rigelk)) |
348 | * Add basic ActivityPub documentation: https://docs.joinpeertube.org/lang/en/devdocs/federation.html ([@rigelk](https://github.com/rigelk)) | 348 | * Add basic ActivityPub documentation ([@rigelk](https://github.com/rigelk)) |
349 | * Add CLI option to run PeerTube without client ([@rigelk](https://github.com/rigelk)) | 349 | * Add CLI option to run PeerTube without client ([@rigelk](https://github.com/rigelk)) |
350 | * Add manpage to peertube CLI ([@rigelk](https://github.com/rigelk)) | 350 | * Add manpage to peertube CLI ([@rigelk](https://github.com/rigelk)) |
351 | * Make backups of files in optimize-old-videos script ([@Nutomic](https://github.com/nutomic)) | 351 | * Make backups of files in optimize-old-videos script ([@Nutomic](https://github.com/nutomic)) |
@@ -430,8 +430,8 @@ and update your [.env](https://github.com/Chocobozzz/PeerTube/blob/develop/suppo | |||
430 | 430 | ||
431 | ### Maintenance | 431 | ### Maintenance |
432 | 432 | ||
433 | * Improve REST API documentation: https://docs.joinpeertube.org/api.html ([@rigelk](https://github.com/rigelk)) | 433 | * Improve REST API documentation ([@rigelk](https://github.com/rigelk)) |
434 | * Add basic ActivityPub documentation: https://docs.joinpeertube.org/lang/en/devdocs/federation.html ([@rigelk](https://github.com/rigelk)) | 434 | * Add basic ActivityPub documentation ([@rigelk](https://github.com/rigelk)) |
435 | * Add CLI option to run PeerTube without client ([@rigelk](https://github.com/rigelk)) | 435 | * Add CLI option to run PeerTube without client ([@rigelk](https://github.com/rigelk)) |
436 | * Add manpage to peertube CLI ([@rigelk](https://github.com/rigelk)) | 436 | * Add manpage to peertube CLI ([@rigelk](https://github.com/rigelk)) |
437 | * Make backups of files in optimize-old-videos script ([@Nutomic](https://github.com/nutomic)) | 437 | * Make backups of files in optimize-old-videos script ([@Nutomic](https://github.com/nutomic)) |
@@ -645,7 +645,7 @@ This release could contain bugs. Don't expect a stable v1.1.0 until December :) | |||
645 | 645 | ||
646 | ### Features | 646 | ### Features |
647 | 647 | ||
648 | * Video redundancy system (experimental, see [the doc](https://docs.joinpeertube.org/lang/en/devdocs/architecture.html#redundancy-between-instances)) | 648 | * Video redundancy system (experimental) |
649 | * Add peertube script (see [the doc](/support/doc/tools.md#cli-wrapper)) ([@rigelk](https://github.com/rigelk)) | 649 | * Add peertube script (see [the doc](/support/doc/tools.md#cli-wrapper)) ([@rigelk](https://github.com/rigelk)) |
650 | * Improve download modal ([@rigelk](https://github.com/rigelk)) | 650 | * Improve download modal ([@rigelk](https://github.com/rigelk)) |
651 | * Add redirect after login ([@BO41](https://github.com/BO41)) | 651 | * Add redirect after login ([@BO41](https://github.com/BO41)) |
@@ -58,7 +58,7 @@ is named "Framatube". | |||
58 | 58 | ||
59 | Yes, the origin server always seeds videos uploaded on it thanks to | 59 | Yes, 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). |
61 | It can also be helped by other servers using [redundancy](https://docs.joinpeertube.org/lang/en/devdocs/architecture.html#redundancy-between-instances). | 61 | It 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? |
@@ -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"> |
118 | In 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>). | 118 | In 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"> |
121 | Content 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>). | 121 | Content 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 | ||
154 | See the [production guide](/support/doc/production.md), which is the recommended way. | 154 | See 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 | ||
156 | See 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)). | 156 | See 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 | ||
165 | See the [user documentation](https://docs.joinpeertube.org/lang/en/userdocs/). | 165 | See the [user documentation](https://docs.joinpeertube.org/#/use-setup-account). |
166 | 166 | ||
167 | ### Admin documentation | 167 | ### Admin documentation |
168 | 168 | ||
169 | See [how to create your own instance](#package-create-your-own-instance). | 169 | See [how to create your own instance](#package-create-your-own-instance). |
170 | 170 | ||
171 | See the more general [admin documentation](https://docs.joinpeertube.org/lang/en/docs/). | 171 | See 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 | ||
181 | See the [architecture blueprint](https://docs.joinpeertube.org/lang/en/devdocs/architecture.html) for a more detailed explanation of the architectural choices. | 181 | See the [architecture blueprint](https://docs.joinpeertube.org/#/contribute-architecture) for a more detailed explanation of the architectural choices. |
182 | 182 | ||
183 | See our REST API documentation: | 183 | See 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 | ||
187 | See our [ActivityPub documentation](https://docs.joinpeertube.org/lang/en/devdocs/federation.html). | 187 | See 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/e2e/src/po/my-account.ts b/client/e2e/src/po/my-account.ts new file mode 100644 index 000000000..e49372983 --- /dev/null +++ b/client/e2e/src/po/my-account.ts | |||
@@ -0,0 +1,72 @@ | |||
1 | import { by, element } from 'protractor' | ||
2 | |||
3 | export class MyAccountPage { | ||
4 | |||
5 | navigateToMyVideos () { | ||
6 | return element(by.css('a[href="/my-account/videos"]')).click() | ||
7 | } | ||
8 | |||
9 | navigateToMyPlaylists () { | ||
10 | return element(by.css('a[href="/my-account/video-playlists"]')).click() | ||
11 | } | ||
12 | |||
13 | navigateToMyHistory () { | ||
14 | return element(by.css('a[href="/my-account/history/videos"]')).click() | ||
15 | } | ||
16 | |||
17 | // My account Videos | ||
18 | |||
19 | getLastVideoName () { | ||
20 | return this.getAllVideoNameElements().first().getText() | ||
21 | } | ||
22 | |||
23 | removeLastVideo () { | ||
24 | return this.getLastVideoElement().element(by.css('my-delete-button')).click() | ||
25 | } | ||
26 | |||
27 | validRemove () { | ||
28 | return element(by.css('.action-button-submit')).click() | ||
29 | } | ||
30 | |||
31 | countVideos () { | ||
32 | return this.getAllVideoNameElements().count() | ||
33 | } | ||
34 | |||
35 | // My account playlists | ||
36 | |||
37 | getLastUpdatedPlaylistName () { | ||
38 | return this.getLastUpdatedPlaylist().element(by.css('.miniature-name')).getText() | ||
39 | } | ||
40 | |||
41 | getLastUpdatedPlaylistVideosText () { | ||
42 | return this.getLastUpdatedPlaylist().element(by.css('.miniature-playlist-info-overlay')).getText() | ||
43 | } | ||
44 | |||
45 | clickOnLastUpdatedPlaylist () { | ||
46 | return this.getLastUpdatedPlaylist().element(by.css('.miniature-thumbnail')).click() | ||
47 | } | ||
48 | |||
49 | countTotalPlaylistElements () { | ||
50 | return element.all(by.css('my-video-playlist-element-miniature')).count() | ||
51 | } | ||
52 | |||
53 | playPlaylist () { | ||
54 | return element(by.css('.playlist-info .miniature-thumbnail')).click() | ||
55 | } | ||
56 | |||
57 | // My account Videos | ||
58 | |||
59 | private getLastVideoElement () { | ||
60 | return element.all(by.css('.video')).first() | ||
61 | } | ||
62 | |||
63 | private getAllVideoNameElements () { | ||
64 | return element.all(by.css('.video-miniature-name')) | ||
65 | } | ||
66 | |||
67 | // My account playlists | ||
68 | |||
69 | private getLastUpdatedPlaylist () { | ||
70 | return element.all(by.css('my-video-playlist-miniature')).first() | ||
71 | } | ||
72 | } | ||
diff --git a/client/e2e/src/po/video-update.po.ts b/client/e2e/src/po/video-update.po.ts new file mode 100644 index 000000000..4de3b1b1d --- /dev/null +++ b/client/e2e/src/po/video-update.po.ts | |||
@@ -0,0 +1,20 @@ | |||
1 | import { by, element } from 'protractor' | ||
2 | |||
3 | export class VideoUpdatePage { | ||
4 | |||
5 | async updateName (videoName: string) { | ||
6 | const nameInput = element(by.css('input#name')) | ||
7 | await nameInput.clear() | ||
8 | await nameInput.sendKeys(videoName) | ||
9 | } | ||
10 | |||
11 | async validUpdate () { | ||
12 | const submitButton = await this.getSubmitButton() | ||
13 | |||
14 | return submitButton.click() | ||
15 | } | ||
16 | |||
17 | private getSubmitButton () { | ||
18 | return element(by.css('.submit-button:not(.disabled) input')) | ||
19 | } | ||
20 | } | ||
diff --git a/client/e2e/src/po/video-watch.po.ts b/client/e2e/src/po/video-watch.po.ts index 5f61d5668..9bb0a3919 100644 --- a/client/e2e/src/po/video-watch.po.ts +++ b/client/e2e/src/po/video-watch.po.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { browser, by, element } from 'protractor' | 1 | import { browser, by, element, ElementFinder, ExpectedConditions } from 'protractor' |
2 | 2 | ||
3 | export class VideoWatchPage { | 3 | export class VideoWatchPage { |
4 | async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) { | 4 | async goOnVideosList (isMobileDevice: boolean, isSafari: boolean) { |
@@ -44,6 +44,10 @@ export class VideoWatchPage { | |||
44 | .then(seconds => parseInt(seconds, 10)) | 44 | .then(seconds => parseInt(seconds, 10)) |
45 | } | 45 | } |
46 | 46 | ||
47 | getVideoName () { | ||
48 | return this.getVideoNameElement().getText() | ||
49 | } | ||
50 | |||
47 | async playAndPauseVideo (isAutoplay: boolean, isMobileDevice: boolean) { | 51 | async playAndPauseVideo (isAutoplay: boolean, isMobileDevice: boolean) { |
48 | if (isAutoplay === false) { | 52 | if (isAutoplay === false) { |
49 | const playButton = element(by.css('.vjs-big-play-button')) | 53 | const playButton = element(by.css('.vjs-big-play-button')) |
@@ -101,4 +105,41 @@ export class VideoWatchPage { | |||
101 | async goOnP2PMediaLoaderEmbed () { | 105 | async goOnP2PMediaLoaderEmbed () { |
102 | return browser.get('https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50?mode=p2p-media-loader') | 106 | return browser.get('https://peertube2.cpy.re/videos/embed/969bf103-7818-43b5-94a0-de159e13de50?mode=p2p-media-loader') |
103 | } | 107 | } |
108 | |||
109 | async clickOnUpdate () { | ||
110 | const dropdown = element(by.css('my-video-actions-dropdown .action-button')) | ||
111 | await dropdown.click() | ||
112 | |||
113 | const items: ElementFinder[] = await element.all(by.css('my-video-actions-dropdown .dropdown-menu .dropdown-item')) | ||
114 | |||
115 | for (const item of items) { | ||
116 | const href = await item.getAttribute('href') | ||
117 | |||
118 | if (href && href.includes('/update/')) { | ||
119 | await item.click() | ||
120 | return | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | |||
125 | async clickOnSave () { | ||
126 | return element(by.css('.action-button-save')).click() | ||
127 | } | ||
128 | |||
129 | async saveToWatchLater () { | ||
130 | return element.all(by.css('my-video-add-to-playlist .playlist')).first().click() | ||
131 | } | ||
132 | |||
133 | waitUntilVideoName (name: string, maxTime: number) { | ||
134 | const elem = this.getVideoNameElement() | ||
135 | |||
136 | return browser.wait(ExpectedConditions.textToBePresentInElement(elem, name), maxTime) | ||
137 | } | ||
138 | |||
139 | private getVideoNameElement () { | ||
140 | // We have 2 video info name block, pick the first that is not empty | ||
141 | return element.all(by.css('.video-bottom .video-info-name')) | ||
142 | .filter(e => e.getText().then(t => !!t)) | ||
143 | .first() | ||
144 | } | ||
104 | } | 145 | } |
diff --git a/client/e2e/src/videos.e2e-spec.ts b/client/e2e/src/videos.e2e-spec.ts index 25521cad9..c19ab3092 100644 --- a/client/e2e/src/videos.e2e-spec.ts +++ b/client/e2e/src/videos.e2e-spec.ts | |||
@@ -2,35 +2,56 @@ import { VideoWatchPage } from './po/video-watch.po' | |||
2 | import { VideoUploadPage } from './po/video-upload.po' | 2 | import { VideoUploadPage } from './po/video-upload.po' |
3 | import { LoginPage } from './po/login.po' | 3 | import { LoginPage } from './po/login.po' |
4 | import { browser } from 'protractor' | 4 | import { browser } from 'protractor' |
5 | import { VideoUpdatePage } from './po/video-update.po' | ||
6 | import { MyAccountPage } from './po/my-account' | ||
7 | |||
8 | async function skipIfUploadNotSupported () { | ||
9 | if (await isMobileDevice() || await isSafari()) { | ||
10 | console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.') | ||
11 | return true | ||
12 | } | ||
13 | |||
14 | return false | ||
15 | } | ||
16 | |||
17 | async function isMobileDevice () { | ||
18 | const caps = await browser.getCapabilities() | ||
19 | return caps.get('realMobile') === 'true' || caps.get('realMobile') === true | ||
20 | } | ||
21 | |||
22 | async function isSafari () { | ||
23 | const caps = await browser.getCapabilities() | ||
24 | return caps.get('browserName') && caps.get('browserName').toLowerCase() === 'safari' | ||
25 | } | ||
5 | 26 | ||
6 | describe('Videos workflow', () => { | 27 | describe('Videos workflow', () => { |
7 | let videoWatchPage: VideoWatchPage | 28 | let videoWatchPage: VideoWatchPage |
8 | let pageUploadPage: VideoUploadPage | 29 | let videoUploadPage: VideoUploadPage |
30 | let videoUpdatePage: VideoUpdatePage | ||
31 | let myAccountPage: MyAccountPage | ||
9 | let loginPage: LoginPage | 32 | let loginPage: LoginPage |
33 | |||
10 | const videoName = new Date().getTime() + ' video' | 34 | const videoName = new Date().getTime() + ' video' |
11 | let isMobileDevice = false | 35 | let videoWatchUrl: string |
12 | let isSafari = false | ||
13 | 36 | ||
14 | beforeEach(async () => { | 37 | beforeEach(async () => { |
15 | videoWatchPage = new VideoWatchPage() | 38 | videoWatchPage = new VideoWatchPage() |
16 | pageUploadPage = new VideoUploadPage() | 39 | videoUploadPage = new VideoUploadPage() |
40 | videoUpdatePage = new VideoUpdatePage() | ||
41 | myAccountPage = new MyAccountPage() | ||
17 | loginPage = new LoginPage() | 42 | loginPage = new LoginPage() |
18 | 43 | ||
19 | const caps = await browser.getCapabilities() | 44 | if (await isMobileDevice()) { |
20 | isMobileDevice = caps.get('realMobile') === 'true' || caps.get('realMobile') === true | ||
21 | isSafari = caps.get('browserName') && caps.get('browserName').toLowerCase() === 'safari' | ||
22 | |||
23 | if (isMobileDevice) { | ||
24 | console.log('Mobile device detected.') | 45 | console.log('Mobile device detected.') |
25 | } | 46 | } |
26 | 47 | ||
27 | if (isSafari) { | 48 | if (await isSafari()) { |
28 | console.log('Safari detected.') | 49 | console.log('Safari detected.') |
29 | } | 50 | } |
30 | }) | 51 | }) |
31 | 52 | ||
32 | it('Should log in', () => { | 53 | it('Should log in', async () => { |
33 | if (isMobileDevice || isSafari) { | 54 | if (await isMobileDevice() || await isSafari()) { |
34 | console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.') | 55 | console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.') |
35 | return | 56 | return |
36 | } | 57 | } |
@@ -39,24 +60,18 @@ describe('Videos workflow', () => { | |||
39 | }) | 60 | }) |
40 | 61 | ||
41 | it('Should upload a video', async () => { | 62 | it('Should upload a video', async () => { |
42 | if (isMobileDevice || isSafari) { | 63 | if (await skipIfUploadNotSupported()) return |
43 | console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.') | ||
44 | return | ||
45 | } | ||
46 | 64 | ||
47 | await pageUploadPage.navigateTo() | 65 | await videoUploadPage.navigateTo() |
48 | 66 | ||
49 | await pageUploadPage.uploadVideo() | 67 | await videoUploadPage.uploadVideo() |
50 | return pageUploadPage.validSecondUploadStep(videoName) | 68 | return videoUploadPage.validSecondUploadStep(videoName) |
51 | }) | 69 | }) |
52 | 70 | ||
53 | it('Should list videos', async () => { | 71 | it('Should list videos', async () => { |
54 | await videoWatchPage.goOnVideosList(isMobileDevice, isSafari) | 72 | await videoWatchPage.goOnVideosList(await isMobileDevice(), await isSafari()) |
55 | 73 | ||
56 | if (isMobileDevice || isSafari) { | 74 | if (await skipIfUploadNotSupported()) return |
57 | console.log('Skipping because we are on a real device or Safari and BrowserStack does not support file upload.') | ||
58 | return | ||
59 | } | ||
60 | 75 | ||
61 | const videoNames = videoWatchPage.getVideosListName() | 76 | const videoNames = videoWatchPage.getVideosListName() |
62 | expect(videoNames).toContain(videoName) | 77 | expect(videoNames).toContain(videoName) |
@@ -65,14 +80,16 @@ describe('Videos workflow', () => { | |||
65 | it('Should go on video watch page', async () => { | 80 | it('Should go on video watch page', async () => { |
66 | let videoNameToExcept = videoName | 81 | let videoNameToExcept = videoName |
67 | 82 | ||
68 | if (isMobileDevice || isSafari) videoNameToExcept = await videoWatchPage.clickOnFirstVideo() | 83 | if (await isMobileDevice() || await isSafari()) videoNameToExcept = await videoWatchPage.clickOnFirstVideo() |
69 | else await videoWatchPage.clickOnVideo(videoName) | 84 | else await videoWatchPage.clickOnVideo(videoName) |
70 | 85 | ||
71 | return videoWatchPage.waitWatchVideoName(videoNameToExcept, isMobileDevice, isSafari) | 86 | return videoWatchPage.waitWatchVideoName(videoNameToExcept, await isMobileDevice(), await isSafari()) |
72 | }) | 87 | }) |
73 | 88 | ||
74 | it('Should play the video', async () => { | 89 | it('Should play the video', async () => { |
75 | await videoWatchPage.playAndPauseVideo(true, isMobileDevice) | 90 | videoWatchUrl = await browser.getCurrentUrl() |
91 | |||
92 | await videoWatchPage.playAndPauseVideo(true, await isMobileDevice()) | ||
76 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) | 93 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) |
77 | }) | 94 | }) |
78 | 95 | ||
@@ -81,7 +98,7 @@ describe('Videos workflow', () => { | |||
81 | 98 | ||
82 | await videoWatchPage.goOnAssociatedEmbed() | 99 | await videoWatchPage.goOnAssociatedEmbed() |
83 | 100 | ||
84 | await videoWatchPage.playAndPauseVideo(false, isMobileDevice) | 101 | await videoWatchPage.playAndPauseVideo(false, await isMobileDevice()) |
85 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) | 102 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) |
86 | 103 | ||
87 | await browser.waitForAngularEnabled(true) | 104 | await browser.waitForAngularEnabled(true) |
@@ -92,9 +109,93 @@ describe('Videos workflow', () => { | |||
92 | 109 | ||
93 | await videoWatchPage.goOnP2PMediaLoaderEmbed() | 110 | await videoWatchPage.goOnP2PMediaLoaderEmbed() |
94 | 111 | ||
95 | await videoWatchPage.playAndPauseVideo(false, isMobileDevice) | 112 | await videoWatchPage.playAndPauseVideo(false, await isMobileDevice()) |
96 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) | 113 | expect(videoWatchPage.getWatchVideoPlayerCurrentTime()).toBeGreaterThanOrEqual(2) |
97 | 114 | ||
98 | await browser.waitForAngularEnabled(true) | 115 | await browser.waitForAngularEnabled(true) |
99 | }) | 116 | }) |
117 | |||
118 | it('Should update the video', async () => { | ||
119 | if (await skipIfUploadNotSupported()) return | ||
120 | |||
121 | await browser.get(videoWatchUrl) | ||
122 | |||
123 | await videoWatchPage.clickOnUpdate() | ||
124 | |||
125 | await videoUpdatePage.updateName('my new name') | ||
126 | |||
127 | await videoUpdatePage.validUpdate() | ||
128 | |||
129 | const name = await videoWatchPage.getVideoName() | ||
130 | expect(name).toEqual('my new name') | ||
131 | }) | ||
132 | |||
133 | it('Should add the video in my playlist', async () => { | ||
134 | if (await skipIfUploadNotSupported()) return | ||
135 | |||
136 | await videoWatchPage.clickOnSave() | ||
137 | await videoWatchPage.saveToWatchLater() | ||
138 | |||
139 | await videoUploadPage.navigateTo() | ||
140 | |||
141 | await videoUploadPage.uploadVideo() | ||
142 | await videoUploadPage.validSecondUploadStep('second video') | ||
143 | |||
144 | await videoWatchPage.clickOnSave() | ||
145 | await videoWatchPage.saveToWatchLater() | ||
146 | }) | ||
147 | |||
148 | it('Should have the watch later playlist in my account', async () => { | ||
149 | if (await skipIfUploadNotSupported()) return | ||
150 | |||
151 | await myAccountPage.navigateToMyPlaylists() | ||
152 | |||
153 | const name = await myAccountPage.getLastUpdatedPlaylistName() | ||
154 | expect(name).toEqual('Watch later') | ||
155 | |||
156 | const videosNumberText = await myAccountPage.getLastUpdatedPlaylistVideosText() | ||
157 | expect(videosNumberText).toEqual('2 videos') | ||
158 | |||
159 | await myAccountPage.clickOnLastUpdatedPlaylist() | ||
160 | |||
161 | const count = await myAccountPage.countTotalPlaylistElements() | ||
162 | expect(count).toEqual(2) | ||
163 | }) | ||
164 | |||
165 | it('Should watch the playlist', async () => { | ||
166 | if (await skipIfUploadNotSupported()) return | ||
167 | |||
168 | await myAccountPage.playPlaylist() | ||
169 | |||
170 | await videoWatchPage.waitUntilVideoName('second video', 20000 * 1000) | ||
171 | }) | ||
172 | |||
173 | it('Should have the video in my account', async () => { | ||
174 | if (await skipIfUploadNotSupported()) return | ||
175 | |||
176 | await myAccountPage.navigateToMyVideos() | ||
177 | |||
178 | const lastVideoName = await myAccountPage.getLastVideoName() | ||
179 | expect(lastVideoName).toEqual('second video') | ||
180 | }) | ||
181 | |||
182 | it('Should delete the last video', async () => { | ||
183 | if (await skipIfUploadNotSupported()) return | ||
184 | |||
185 | await myAccountPage.removeLastVideo() | ||
186 | await myAccountPage.validRemove() | ||
187 | |||
188 | const count = await myAccountPage.countVideos() | ||
189 | expect(count).toEqual(1) | ||
190 | }) | ||
191 | |||
192 | it('Should delete the first video', async () => { | ||
193 | if (await skipIfUploadNotSupported()) return | ||
194 | |||
195 | await myAccountPage.removeLastVideo() | ||
196 | await myAccountPage.validRemove() | ||
197 | |||
198 | const count = await myAccountPage.countVideos() | ||
199 | expect(count).toEqual(0) | ||
200 | }) | ||
100 | }) | 201 | }) |
diff --git a/client/proxy.config.json b/client/proxy.config.json index e5f0dfd61..4a72f1826 100644 --- a/client/proxy.config.json +++ b/client/proxy.config.json | |||
@@ -8,7 +8,8 @@ | |||
8 | "secure": false | 8 | "secure": false |
9 | }, | 9 | }, |
10 | "/socket.io": { | 10 | "/socket.io": { |
11 | "target": "http://localhost:9000", | 11 | "target": "ws://localhost:9000", |
12 | "secure": false | 12 | "secure": false, |
13 | "ws": true | ||
13 | } | 14 | } |
14 | } | 15 | } |
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 | |||
10 | a { | ||
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 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { FollowService } from '@app/shared/instance/follow.service' | ||
3 | import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model' | ||
4 | import { Notifier } from '@app/core' | ||
5 | import { RestService } from '@app/shared' | ||
6 | import { 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 | |||
14 | export 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' | |||
4 | import { AboutComponent } from './about.component' | 4 | import { AboutComponent } from './about.component' |
5 | import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component' | 5 | import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component' |
6 | import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component' | 6 | import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component' |
7 | import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component' | ||
7 | 8 | ||
8 | const aboutRoutes: Routes = [ | 9 | const 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' | |||
6 | import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component' | 6 | import { AboutInstanceComponent } from '@app/+about/about-instance/about-instance.component' |
7 | import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component' | 7 | import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertube.component' |
8 | import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' | 8 | import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' |
9 | import { 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..e9c8179b7 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,25 @@ | |||
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 | <div *ngIf="getVideosOf(videoChannel)" class="videos"> | ||
19 | <div class="no-results" i18n *ngIf="getVideosOf(videoChannel).length === 0">This channel does not have videos.</div> | ||
20 | |||
21 | <my-video-miniature *ngFor="let video of getVideosOf(videoChannel)" [video]="video" [user]="user" [displayVideoActions]="false"></my-video-miniature> | ||
22 | </div> | ||
23 | </div> | ||
24 | </div> | ||
25 | </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..98931f0c2 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,28 @@ | |||
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 | ||
8 | a.video-channel { | 9 | .section { |
9 | @include disable-default-a-behaviour; | 10 | @include miniature-rows; |
10 | 11 | ||
11 | display: inline-block; | 12 | overflow: visible; // For the subscribe dropdown |
12 | text-align: center; | 13 | padding-top: 0 !important; |
13 | color: var(--mainForegroundColor); | ||
14 | margin: 10px 30px; | ||
15 | 14 | ||
16 | img { | 15 | .section-title { |
17 | @include avatar(80px); | 16 | align-items: center; |
18 | |||
19 | margin-bottom: 10px; | ||
20 | } | 17 | } |
21 | 18 | ||
22 | .video-channel-display-name { | 19 | .videos { |
23 | font-size: 20px; | 20 | overflow: hidden; |
24 | font-weight: $font-bold; | ||
25 | } | ||
26 | 21 | ||
27 | .video-channel-followers { | 22 | .no-results { |
28 | font-size: 15px; | 23 | height: 50px; |
24 | } | ||
29 | } | 25 | } |
30 | } \ No newline at end of file | 26 | } |
27 | |||
28 | |||
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..a8d4237e8 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' | |||
3 | import { Account } from '@app/shared/account/account.model' | 3 | import { Account } from '@app/shared/account/account.model' |
4 | import { AccountService } from '@app/shared/account/account.service' | 4 | import { AccountService } from '@app/shared/account/account.service' |
5 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' | 5 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' |
6 | import { flatMap, map, tap } from 'rxjs/operators' | 6 | import { concatMap, map, switchMap, tap } from 'rxjs/operators' |
7 | import { Subscription } from 'rxjs' | 7 | import { from, Subscription } from 'rxjs' |
8 | import { VideoChannel } from '@app/shared/video-channel/video-channel.model' | 8 | import { VideoChannel } from '@app/shared/video-channel/video-channel.model' |
9 | import { Video } from '@app/shared/video/video.model' | ||
10 | import { AuthService } from '@app/core' | ||
11 | import { VideoService } from '@app/shared/video/video.service' | ||
12 | import { VideoSortField } from '@app/shared/video/sort-field.type' | ||
13 | import { 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' | |||
15 | export class AccountVideoChannelsComponent implements OnInit, OnDestroy { | 20 | export 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..45b24eb55 100644 --- a/client/src/app/+accounts/accounts-routing.module.ts +++ b/client/src/app/+accounts/accounts-routing.module.ts | |||
@@ -8,13 +8,17 @@ import { AccountVideoChannelsComponent } from './account-video-channels/account- | |||
8 | 8 | ||
9 | const accountsRoutes: Routes = [ | 9 | const accountsRoutes: Routes = [ |
10 | { | 10 | { |
11 | path: 'peertube', | ||
12 | redirectTo: '/videos/local' | ||
13 | }, | ||
14 | { | ||
11 | path: ':accountId', | 15 | path: ':accountId', |
12 | component: AccountsComponent, | 16 | component: AccountsComponent, |
13 | canActivateChild: [ MetaGuard ], | 17 | canActivateChild: [ MetaGuard ], |
14 | children: [ | 18 | children: [ |
15 | { | 19 | { |
16 | path: '', | 20 | path: '', |
17 | redirectTo: 'videos', | 21 | redirectTo: 'video-channels', |
18 | pathMatch: 'full' | 22 | pathMatch: 'full' |
19 | }, | 23 | }, |
20 | { | 24 | { |
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' | |||
5 | import { SharedModule } from '../shared' | 5 | import { SharedModule } from '../shared' |
6 | import { AdminRoutingModule } from './admin-routing.module' | 6 | import { AdminRoutingModule } from './admin-routing.module' |
7 | import { AdminComponent } from './admin.component' | 7 | import { AdminComponent } from './admin.component' |
8 | import { FollowersListComponent, FollowingAddComponent, FollowsComponent, FollowService } from './follows' | 8 | import { FollowersListComponent, FollowingAddComponent, FollowsComponent } from './follows' |
9 | import { FollowingListComponent } from './follows/following-list/following-list.component' | 9 | import { FollowingListComponent } from './follows/following-list/following-list.component' |
10 | import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersComponent, UserUpdateComponent } from './users' | 10 | import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersComponent, UserUpdateComponent } from './users' |
11 | import { | 11 | import { |
@@ -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..d5b625d9c 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"> |
@@ -301,8 +309,8 @@ | |||
301 | <ng-container formGroupName="resolutions"> | 309 | <ng-container formGroupName="resolutions"> |
302 | <div class="form-group" *ngFor="let resolution of resolutions"> | 310 | <div class="form-group" *ngFor="let resolution of resolutions"> |
303 | <my-peertube-checkbox | 311 | <my-peertube-checkbox |
304 | [inputName]="getResolutionKey(resolution)" [formControlName]="resolution" | 312 | [inputName]="getResolutionKey(resolution.id)" [formControlName]="resolution.id" |
305 | i18n-labelText labelText="Resolution {{resolution}} enabled" | 313 | i18n-labelText labelText="Resolution {{resolution.label}} enabled" |
306 | ></my-peertube-checkbox> | 314 | ></my-peertube-checkbox> |
307 | </div> | 315 | </div> |
308 | </ng-container> | 316 | </ng-container> |
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..055bae851 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 | |||
@@ -15,7 +15,7 @@ import { FormValidatorService } from '@app/shared/forms/form-validators/form-val | |||
15 | export class EditCustomConfigComponent extends FormReactive implements OnInit { | 15 | export class EditCustomConfigComponent extends FormReactive implements OnInit { |
16 | customConfig: CustomConfig | 16 | customConfig: CustomConfig |
17 | 17 | ||
18 | resolutions: string[] = [] | 18 | resolutions: { id: string, label: string }[] = [] |
19 | transcodingThreadOptions: { label: string, value: number }[] = [] | 19 | transcodingThreadOptions: { label: string, value: number }[] = [] |
20 | 20 | ||
21 | constructor ( | 21 | constructor ( |
@@ -30,11 +30,30 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
30 | super() | 30 | super() |
31 | 31 | ||
32 | this.resolutions = [ | 32 | this.resolutions = [ |
33 | this.i18n('240p'), | 33 | { |
34 | this.i18n('360p'), | 34 | id: '240p', |
35 | this.i18n('480p'), | 35 | label: this.i18n('240p') |
36 | this.i18n('720p'), | 36 | }, |
37 | this.i18n('1080p') | 37 | { |
38 | id: '360p', | ||
39 | label: this.i18n('360p') | ||
40 | }, | ||
41 | { | ||
42 | id: '480p', | ||
43 | label: this.i18n('480p') | ||
44 | }, | ||
45 | { | ||
46 | id: '720p', | ||
47 | label: this.i18n('720p') | ||
48 | }, | ||
49 | { | ||
50 | id: '1080p', | ||
51 | label: this.i18n('1080p') | ||
52 | }, | ||
53 | { | ||
54 | id: '2160p', | ||
55 | label: this.i18n('2160p') | ||
56 | } | ||
38 | ] | 57 | ] |
39 | 58 | ||
40 | this.transcodingThreadOptions = [ | 59 | this.transcodingThreadOptions = [ |
@@ -116,6 +135,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
116 | enabled: null, | 135 | enabled: null, |
117 | threads: this.customConfigValidatorsService.TRANSCODING_THREADS, | 136 | threads: this.customConfigValidatorsService.TRANSCODING_THREADS, |
118 | allowAdditionalExtensions: null, | 137 | allowAdditionalExtensions: null, |
138 | allowAudioFiles: null, | ||
119 | resolutions: {} | 139 | resolutions: {} |
120 | }, | 140 | }, |
121 | autoBlacklist: { | 141 | autoBlacklist: { |
@@ -139,8 +159,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
139 | } | 159 | } |
140 | } | 160 | } |
141 | for (const resolution of this.resolutions) { | 161 | for (const resolution of this.resolutions) { |
142 | defaultValues.transcoding.resolutions[resolution] = 'false' | 162 | defaultValues.transcoding.resolutions[resolution.id] = 'false' |
143 | formGroupData.transcoding.resolutions[resolution] = null | 163 | formGroupData.transcoding.resolutions[resolution.id] = null |
144 | } | 164 | } |
145 | 165 | ||
146 | this.buildForm(formGroupData) | 166 | this.buildForm(formGroupData) |
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' | |||
3 | import { SortMeta } from 'primeng/primeng' | 3 | import { SortMeta } from 'primeng/primeng' |
4 | import { ActorFollow } from '../../../../../../shared/models/actors/follow.model' | 4 | import { ActorFollow } from '../../../../../../shared/models/actors/follow.model' |
5 | import { RestPagination, RestTable } from '../../../shared' | 5 | import { RestPagination, RestTable } from '../../../shared' |
6 | import { FollowService } from '../shared' | 6 | import { FollowService } from '@app/shared/instance/follow.service' |
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | 7 | import { 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' | |||
3 | import { Notifier } from '@app/core' | 3 | import { Notifier } from '@app/core' |
4 | import { ConfirmService } from '../../../core' | 4 | import { ConfirmService } from '../../../core' |
5 | import { validateHost } from '../../../shared' | 5 | import { validateHost } from '../../../shared' |
6 | import { FollowService } from '../shared' | 6 | import { FollowService } from '@app/shared/instance/follow.service' |
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | 7 | import { 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' | |||
4 | import { ActorFollow } from '../../../../../../shared/models/actors/follow.model' | 4 | import { ActorFollow } from '../../../../../../shared/models/actors/follow.model' |
5 | import { ConfirmService } from '../../../core/confirm/confirm.service' | 5 | import { ConfirmService } from '../../../core/confirm/confirm.service' |
6 | import { RestPagination, RestTable } from '../../../shared' | 6 | import { RestPagination, RestTable } from '../../../shared' |
7 | import { FollowService } from '../shared' | 7 | import { FollowService } from '@app/shared/instance/follow.service' |
8 | import { I18n } from '@ngx-translate/i18n-polyfill' | 8 | import { 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 @@ | |||
1 | export * from './following-add' | 1 | export * from './following-add' |
2 | export * from './followers-list' | 2 | export * from './followers-list' |
3 | export * from './following-list' | 3 | export * from './following-list' |
4 | export * from './shared' | ||
5 | export * from './follows.component' | 4 | export * from './follows.component' |
6 | export * from './follows.routes' | 5 | export * 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 @@ | |||
1 | export * 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' | |||
7 | export abstract class UserEdit extends FormReactive { | 7 | export 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-settings/my-account-change-email/index.ts b/client/src/app/+my-account/my-account-settings/my-account-change-email/index.ts new file mode 100644 index 000000000..f42af361e --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './my-account-change-email.component' | |||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html new file mode 100644 index 000000000..5492cdf22 --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.html | |||
@@ -0,0 +1,36 @@ | |||
1 | <div *ngIf="error" class="alert alert-danger">{{ error }}</div> | ||
2 | <div *ngIf="success" class="alert alert-success">{{ success }}</div> | ||
3 | |||
4 | <div i18n class="current-email"> | ||
5 | Your current email is <span class="email">{{ user.email }}</span> | ||
6 | </div> | ||
7 | |||
8 | <div i18n class="pending-email" *ngIf="user.pendingEmail"> | ||
9 | <span class="email">{{ user.pendingEmail }}</span> is awaiting email verification | ||
10 | </div> | ||
11 | |||
12 | <form role="form" class="change-email" (ngSubmit)="changeEmail()" [formGroup]="form"> | ||
13 | |||
14 | <div class="form-group"> | ||
15 | <label i18n for="new-email">New email</label> | ||
16 | <input | ||
17 | type="email" id="new-email" i18n-placeholder placeholder="Your new email" | ||
18 | formControlName="new-email" [ngClass]="{ 'input-error': formErrors['new-email'] }" | ||
19 | > | ||
20 | <div *ngIf="formErrors['new-email']" class="form-error"> | ||
21 | {{ formErrors['new-email'] }} | ||
22 | </div> | ||
23 | </div> | ||
24 | |||
25 | <div class="form-group"> | ||
26 | <input | ||
27 | type="password" id="password" i18n-placeholder placeholder="Your password" | ||
28 | formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }" | ||
29 | > | ||
30 | <div *ngIf="formErrors['password']" class="form-error"> | ||
31 | {{ formErrors['password'] }} | ||
32 | </div> | ||
33 | </div> | ||
34 | |||
35 | <input type="submit" i18n-value value="Change email" [disabled]="!form.valid"> | ||
36 | </form> | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.scss b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.scss new file mode 100644 index 000000000..81eba3ec9 --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.scss | |||
@@ -0,0 +1,24 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | input[type=password], | ||
5 | input[type=email] { | ||
6 | @include peertube-input-text(340px); | ||
7 | |||
8 | display: block; | ||
9 | } | ||
10 | |||
11 | input[type=submit] { | ||
12 | @include peertube-button; | ||
13 | @include orange-button; | ||
14 | } | ||
15 | |||
16 | .current-email, | ||
17 | .pending-email { | ||
18 | font-size: 16px; | ||
19 | margin: 15px 0; | ||
20 | |||
21 | .email { | ||
22 | font-weight: $font-semibold; | ||
23 | } | ||
24 | } | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts new file mode 100644 index 000000000..ec7cf935c --- /dev/null +++ b/client/src/app/+my-account/my-account-settings/my-account-change-email/my-account-change-email.component.ts | |||
@@ -0,0 +1,73 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { AuthService, Notifier, ServerService } from '@app/core' | ||
3 | import { FormReactive, UserService } from '../../../shared' | ||
4 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
5 | import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' | ||
6 | import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service' | ||
7 | import { User } from '../../../../../../shared' | ||
8 | import { tap } from 'rxjs/operators' | ||
9 | |||
10 | @Component({ | ||
11 | selector: 'my-account-change-email', | ||
12 | templateUrl: './my-account-change-email.component.html', | ||
13 | styleUrls: [ './my-account-change-email.component.scss' ] | ||
14 | }) | ||
15 | export class MyAccountChangeEmailComponent extends FormReactive implements OnInit { | ||
16 | error: string = null | ||
17 | success: string = null | ||
18 | user: User = null | ||
19 | |||
20 | constructor ( | ||
21 | protected formValidatorService: FormValidatorService, | ||
22 | private userValidatorsService: UserValidatorsService, | ||
23 | private notifier: Notifier, | ||
24 | private authService: AuthService, | ||
25 | private userService: UserService, | ||
26 | private serverService: ServerService, | ||
27 | private i18n: I18n | ||
28 | ) { | ||
29 | super() | ||
30 | } | ||
31 | |||
32 | ngOnInit () { | ||
33 | this.buildForm({ | ||
34 | 'new-email': this.userValidatorsService.USER_EMAIL, | ||
35 | 'password': this.userValidatorsService.USER_PASSWORD | ||
36 | }) | ||
37 | |||
38 | this.user = this.authService.getUser() | ||
39 | } | ||
40 | |||
41 | changeEmail () { | ||
42 | this.error = null | ||
43 | this.success = null | ||
44 | |||
45 | const password = this.form.value[ 'password' ] | ||
46 | const email = this.form.value[ 'new-email' ] | ||
47 | |||
48 | this.userService.changeEmail(password, email) | ||
49 | .pipe( | ||
50 | tap(() => this.authService.refreshUserInformation()) | ||
51 | ) | ||
52 | .subscribe( | ||
53 | () => { | ||
54 | this.form.reset() | ||
55 | |||
56 | if (this.serverService.getConfig().signup.requiresEmailVerification) { | ||
57 | this.success = this.i18n('Please check your emails to verify your new email.') | ||
58 | } else { | ||
59 | this.success = this.i18n('Email updated.') | ||
60 | } | ||
61 | }, | ||
62 | |||
63 | err => { | ||
64 | if (err.status === 401) { | ||
65 | this.error = this.i18n('You current password is invalid.') | ||
66 | return | ||
67 | } | ||
68 | |||
69 | this.error = err.message | ||
70 | } | ||
71 | ) | ||
72 | } | ||
73 | } | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.html b/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.html index ae797d1bc..a39061ee3 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.html +++ b/client/src/app/+my-account/my-account-settings/my-account-change-password/my-account-change-password.component.html | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | <form role="form" (ngSubmit)="changePassword()" [formGroup]="form"> | 3 | <form role="form" (ngSubmit)="changePassword()" [formGroup]="form"> |
4 | 4 | ||
5 | <label i18n for="new-password">Change password</label> | 5 | <label i18n for="current-password">Change password</label> |
6 | <input | 6 | <input |
7 | type="password" id="current-password" i18n-placeholder placeholder="Current password" | 7 | type="password" id="current-password" i18n-placeholder placeholder="Current password" |
8 | formControlName="current-password" [ngClass]="{ 'input-error': formErrors['current-password'] }" | 8 | formControlName="current-password" [ngClass]="{ 'input-error': formErrors['current-password'] }" |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts index a9503ed1b..fcad5a6c2 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-profile/my-account-profile.component.ts | |||
@@ -30,7 +30,7 @@ export class MyAccountProfileComponent extends FormReactive implements OnInit { | |||
30 | 30 | ||
31 | ngOnInit () { | 31 | ngOnInit () { |
32 | this.buildForm({ | 32 | this.buildForm({ |
33 | 'display-name': this.userValidatorsService.USER_DISPLAY_NAME, | 33 | 'display-name': this.userValidatorsService.USER_DISPLAY_NAME_REQUIRED, |
34 | description: this.userValidatorsService.USER_DESCRIPTION | 34 | description: this.userValidatorsService.USER_DESCRIPTION |
35 | }) | 35 | }) |
36 | 36 | ||
diff --git a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html index ad64f28fe..f93d41110 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-settings.component.html +++ b/client/src/app/+my-account/my-account-settings/my-account-settings.component.html | |||
@@ -13,6 +13,9 @@ | |||
13 | <div i18n class="account-title">Password</div> | 13 | <div i18n class="account-title">Password</div> |
14 | <my-account-change-password></my-account-change-password> | 14 | <my-account-change-password></my-account-change-password> |
15 | 15 | ||
16 | <div i18n class="account-title">Email</div> | ||
17 | <my-account-change-email></my-account-change-email> | ||
18 | |||
16 | <div i18n class="account-title">Video settings</div> | 19 | <div i18n class="account-title">Video settings</div> |
17 | <my-account-video-settings [user]="user" [userInformationLoaded]="userInformationLoaded"></my-account-video-settings> | 20 | <my-account-video-settings [user]="user" [userInformationLoaded]="userInformationLoaded"></my-account-video-settings> |
18 | 21 | ||
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 | |||
7 | import { VideoPlaylistValidatorsService } from '@app/shared' | 7 | import { VideoPlaylistValidatorsService } from '@app/shared' |
8 | import { VideoPlaylistCreate } from '@shared/models/videos/playlist/video-playlist-create.model' | 8 | import { VideoPlaylistCreate } from '@shared/models/videos/playlist/video-playlist-create.model' |
9 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' | 9 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' |
10 | import { VideoConstant } from '@shared/models' | ||
11 | import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model' | 10 | import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model' |
12 | import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils' | 11 | import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils' |
13 | 12 | ||
@@ -18,7 +17,6 @@ import { populateAsyncUserVideoChannels } from '@app/shared/misc/utils' | |||
18 | }) | 17 | }) |
19 | export class MyAccountVideoPlaylistCreateComponent extends MyAccountVideoPlaylistEdit implements OnInit { | 18 | export 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 @@ | |||
1 | import { FormReactive } from '@app/shared' | 1 | import { FormReactive } from '@app/shared' |
2 | import { VideoChannel } from '@app/shared/video-channel/video-channel.model' | ||
3 | import { ServerService } from '@app/core' | ||
4 | import { VideoPlaylist } from '@shared/models/videos/playlist/video-playlist.model' | 2 | import { VideoPlaylist } from '@shared/models/videos/playlist/video-playlist.model' |
3 | import { VideoConstant, VideoPlaylistPrivacy } from '@shared/models' | ||
5 | 4 | ||
6 | export abstract class MyAccountVideoPlaylistEdit extends FormReactive { | 5 | export 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' | |||
9 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' | 9 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' |
10 | import { VideoPlaylistValidatorsService } from '@app/shared' | 10 | import { VideoPlaylistValidatorsService } from '@app/shared' |
11 | import { VideoPlaylistUpdate } from '@shared/models/videos/playlist/video-playlist-update.model' | 11 | import { VideoPlaylistUpdate } from '@shared/models/videos/playlist/video-playlist-update.model' |
12 | import { VideoConstant } from '@shared/models' | ||
13 | import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model' | ||
14 | import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' | 12 | import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' |
13 | import { 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' | |||
21 | export class MyAccountVideoPlaylistUpdateComponent extends MyAccountVideoPlaylistEdit implements OnInit, OnDestroy { | 20 | export 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/+my-account/my-account.module.ts b/client/src/app/+my-account/my-account.module.ts index 4a18a9968..ca5b1f7cb 100644 --- a/client/src/app/+my-account/my-account.module.ts +++ b/client/src/app/+my-account/my-account.module.ts | |||
@@ -36,6 +36,7 @@ import { | |||
36 | MyAccountVideoPlaylistElementsComponent | 36 | MyAccountVideoPlaylistElementsComponent |
37 | } from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component' | 37 | } from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-elements.component' |
38 | import { DragDropModule } from '@angular/cdk/drag-drop' | 38 | import { DragDropModule } from '@angular/cdk/drag-drop' |
39 | import { MyAccountChangeEmailComponent } from '@app/+my-account/my-account-settings/my-account-change-email' | ||
39 | 40 | ||
40 | @NgModule({ | 41 | @NgModule({ |
41 | imports: [ | 42 | imports: [ |
@@ -54,7 +55,10 @@ import { DragDropModule } from '@angular/cdk/drag-drop' | |||
54 | MyAccountChangePasswordComponent, | 55 | MyAccountChangePasswordComponent, |
55 | MyAccountVideoSettingsComponent, | 56 | MyAccountVideoSettingsComponent, |
56 | MyAccountProfileComponent, | 57 | MyAccountProfileComponent, |
58 | MyAccountChangeEmailComponent, | ||
59 | |||
57 | MyAccountVideosComponent, | 60 | MyAccountVideosComponent, |
61 | |||
58 | VideoChangeOwnershipComponent, | 62 | VideoChangeOwnershipComponent, |
59 | MyAccountOwnershipComponent, | 63 | MyAccountOwnershipComponent, |
60 | MyAccountAcceptOwnershipComponent, | 64 | MyAccountAcceptOwnershipComponent, |
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 | |||
7 | header { | ||
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 @@ | |||
1 | import { Component } from '@angular/core' | ||
2 | import { 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 | }) | ||
10 | export 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 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router' | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | import { MetaGuard } from '@ngx-meta/core' | 3 | import { MetaGuard } from '@ngx-meta/core' |
4 | import { SignupComponent } from './signup.component' | 4 | import { RegisterComponent } from './register.component' |
5 | import { ServerConfigResolver } from '@app/core/routing/server-config-resolver.service' | 5 | import { ServerConfigResolver } from '@app/core/routing/server-config-resolver.service' |
6 | import { UnloggedGuard } from '@app/core/routing/unlogged-guard.service' | ||
6 | 7 | ||
7 | const signupRoutes: Routes = [ | 8 | const 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 | }) |
27 | export class SignupRoutingModule {} | 28 | export 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..253374f87 --- /dev/null +++ b/client/src/app/+signup/+register/register-step-channel.component.html | |||
@@ -0,0 +1,54 @@ | |||
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="displayName" i18n>Channel display name</label> | ||
16 | |||
17 | <div class="input-group"> | ||
18 | <input | ||
19 | type="text" id="displayName" | ||
20 | formControlName="displayName" [ngClass]="{ 'input-error': formErrors['displayName'] }" | ||
21 | > | ||
22 | </div> | ||
23 | |||
24 | <div *ngIf="formErrors.displayName" class="form-error"> | ||
25 | {{ formErrors.displayName }} | ||
26 | </div> | ||
27 | </div> | ||
28 | |||
29 | <div class="form-group"> | ||
30 | <label for="name" i18n>Channel name</label> | ||
31 | |||
32 | <div class="input-group"> | ||
33 | <input | ||
34 | type="text" id="name" i18n-placeholder placeholder="Example: my_super_channel" | ||
35 | formControlName="name" [ngClass]="{ 'input-error': formErrors['name'] }" | ||
36 | > | ||
37 | <div class="input-group-append"> | ||
38 | <span class="input-group-text">@{{ instanceHost }}</span> | ||
39 | </div> | ||
40 | </div> | ||
41 | |||
42 | <div class="name-information" i18n> | ||
43 | The channel name is a unique identifier of your channel on this instance. It's like an address mail, so other people can find your channel. | ||
44 | </div> | ||
45 | |||
46 | <div *ngIf="formErrors.name" class="form-error"> | ||
47 | {{ formErrors.name }} | ||
48 | </div> | ||
49 | |||
50 | <div *ngIf="isSameThanUsername()" class="form-error" i18n> | ||
51 | Channel name cannot be the same than your account name. You can click on the first step to update your account name. | ||
52 | </div> | ||
53 | </div> | ||
54 | </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..e434b91a7 --- /dev/null +++ b/client/src/app/+signup/+register/register-step-channel.component.ts | |||
@@ -0,0 +1,56 @@ | |||
1 | import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core' | ||
2 | import { AuthService } from '@app/core' | ||
3 | import { FormReactive, UserService, VideoChannelValidatorsService } from '@app/shared' | ||
4 | import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' | ||
5 | import { FormGroup } from '@angular/forms' | ||
6 | import { pairwise } from 'rxjs/operators' | ||
7 | import { concat, of } from 'rxjs' | ||
8 | |||
9 | @Component({ | ||
10 | selector: 'my-register-step-channel', | ||
11 | templateUrl: './register-step-channel.component.html', | ||
12 | styleUrls: [ './register.component.scss' ] | ||
13 | }) | ||
14 | export class RegisterStepChannelComponent extends FormReactive implements OnInit { | ||
15 | @Input() username: string | ||
16 | @Output() formBuilt = new EventEmitter<FormGroup>() | ||
17 | |||
18 | constructor ( | ||
19 | protected formValidatorService: FormValidatorService, | ||
20 | private authService: AuthService, | ||
21 | private userService: UserService, | ||
22 | private videoChannelValidatorsService: VideoChannelValidatorsService | ||
23 | ) { | ||
24 | super() | ||
25 | } | ||
26 | |||
27 | get instanceHost () { | ||
28 | return window.location.host | ||
29 | } | ||
30 | |||
31 | ngOnInit () { | ||
32 | this.buildForm({ | ||
33 | displayName: this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME, | ||
34 | name: this.videoChannelValidatorsService.VIDEO_CHANNEL_NAME | ||
35 | }) | ||
36 | |||
37 | setTimeout(() => this.formBuilt.emit(this.form)) | ||
38 | |||
39 | concat( | ||
40 | of(''), | ||
41 | this.form.get('displayName').valueChanges | ||
42 | ).pipe(pairwise()) | ||
43 | .subscribe(([ oldValue, newValue ]) => this.onDisplayNameChange(oldValue, newValue)) | ||
44 | } | ||
45 | |||
46 | isSameThanUsername () { | ||
47 | return this.username && this.username === this.form.value['name'] | ||
48 | } | ||
49 | |||
50 | private onDisplayNameChange (oldDisplayName: string, newDisplayName: string) { | ||
51 | const name = this.form.value['name'] || '' | ||
52 | |||
53 | const newName = this.userService.getNewUsername(oldDisplayName, newDisplayName, name) | ||
54 | this.form.patchValue({ name: newName }) | ||
55 | } | ||
56 | } | ||
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..47b3be8cc --- /dev/null +++ b/client/src/app/+signup/+register/register-step-user.component.html | |||
@@ -0,0 +1,73 @@ | |||
1 | <form role="form" [formGroup]="form"> | ||
2 | |||
3 | <div class="form-group"> | ||
4 | <label for="displayName" i18n>Display name</label> | ||
5 | |||
6 | <div class="input-group"> | ||
7 | <input | ||
8 | type="text" id="displayName" placeholder="John Doe" | ||
9 | formControlName="displayName" [ngClass]="{ 'input-error': formErrors['displayName'] }" | ||
10 | > | ||
11 | </div> | ||
12 | |||
13 | <div *ngIf="formErrors.displayName" class="form-error"> | ||
14 | {{ formErrors.displayName }} | ||
15 | </div> | ||
16 | </div> | ||
17 | |||
18 | <div class="form-group"> | ||
19 | <label for="username" i18n>Username</label> | ||
20 | |||
21 | <div class="input-group"> | ||
22 | <input | ||
23 | type="text" id="username" i18n-placeholder placeholder="Example: jane_doe" | ||
24 | formControlName="username" [ngClass]="{ 'input-error': formErrors['username'] }" | ||
25 | > | ||
26 | <div class="input-group-append"> | ||
27 | <span class="input-group-text">@{{ instanceHost }}</span> | ||
28 | </div> | ||
29 | </div> | ||
30 | |||
31 | <div class="name-information" i18n> | ||
32 | The username is a unique identifier of your account on this instance. It's like an address mail, so other people can find you. | ||
33 | </div> | ||
34 | |||
35 | <div *ngIf="formErrors.username" class="form-error"> | ||
36 | {{ formErrors.username }} | ||
37 | </div> | ||
38 | </div> | ||
39 | |||
40 | <div class="form-group"> | ||
41 | <label for="email" i18n>Email</label> | ||
42 | <input | ||
43 | type="text" id="email" i18n-placeholder placeholder="Email" | ||
44 | formControlName="email" [ngClass]="{ 'input-error': formErrors['email'] }" | ||
45 | > | ||
46 | <div *ngIf="formErrors.email" class="form-error"> | ||
47 | {{ formErrors.email }} | ||
48 | </div> | ||
49 | </div> | ||
50 | |||
51 | <div class="form-group"> | ||
52 | <label for="password" i18n>Password</label> | ||
53 | <input | ||
54 | type="password" id="password" i18n-placeholder placeholder="Password" | ||
55 | formControlName="password" [ngClass]="{ 'input-error': formErrors['password'] }" | ||
56 | > | ||
57 | <div *ngIf="formErrors.password" class="form-error"> | ||
58 | {{ formErrors.password }} | ||
59 | </div> | ||
60 | </div> | ||
61 | |||
62 | <div class="form-group form-group-terms"> | ||
63 | <my-peertube-checkbox | ||
64 | inputName="terms" formControlName="terms" | ||
65 | i18n-labelHtml | ||
66 | 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" | ||
67 | ></my-peertube-checkbox> | ||
68 | |||
69 | <div *ngIf="formErrors.terms" class="form-error"> | ||
70 | {{ formErrors.terms }} | ||
71 | </div> | ||
72 | </div> | ||
73 | </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..3b71fd3c4 --- /dev/null +++ b/client/src/app/+signup/+register/register-step-user.component.ts | |||
@@ -0,0 +1,54 @@ | |||
1 | import { Component, EventEmitter, OnInit, Output } from '@angular/core' | ||
2 | import { AuthService } from '@app/core' | ||
3 | import { FormReactive, UserService, UserValidatorsService } from '@app/shared' | ||
4 | import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' | ||
5 | import { FormGroup } from '@angular/forms' | ||
6 | import { pairwise } from 'rxjs/operators' | ||
7 | import { concat, of } from 'rxjs' | ||
8 | |||
9 | @Component({ | ||
10 | selector: 'my-register-step-user', | ||
11 | templateUrl: './register-step-user.component.html', | ||
12 | styleUrls: [ './register.component.scss' ] | ||
13 | }) | ||
14 | export class RegisterStepUserComponent extends FormReactive implements OnInit { | ||
15 | @Output() formBuilt = new EventEmitter<FormGroup>() | ||
16 | |||
17 | constructor ( | ||
18 | protected formValidatorService: FormValidatorService, | ||
19 | private authService: AuthService, | ||
20 | private userService: UserService, | ||
21 | private userValidatorsService: UserValidatorsService | ||
22 | ) { | ||
23 | super() | ||
24 | } | ||
25 | |||
26 | get instanceHost () { | ||
27 | return window.location.host | ||
28 | } | ||
29 | |||
30 | ngOnInit () { | ||
31 | this.buildForm({ | ||
32 | displayName: this.userValidatorsService.USER_DISPLAY_NAME_REQUIRED, | ||
33 | username: this.userValidatorsService.USER_USERNAME, | ||
34 | password: this.userValidatorsService.USER_PASSWORD, | ||
35 | email: this.userValidatorsService.USER_EMAIL, | ||
36 | terms: this.userValidatorsService.USER_TERMS | ||
37 | }) | ||
38 | |||
39 | setTimeout(() => this.formBuilt.emit(this.form)) | ||
40 | |||
41 | concat( | ||
42 | of(''), | ||
43 | this.form.get('displayName').valueChanges | ||
44 | ).pipe(pairwise()) | ||
45 | .subscribe(([ oldValue, newValue ]) => this.onDisplayNameChange(oldValue, newValue)) | ||
46 | } | ||
47 | |||
48 | private onDisplayNameChange (oldDisplayName: string, newDisplayName: string) { | ||
49 | const username = this.form.value['username'] || '' | ||
50 | |||
51 | const newUsername = this.userService.getNewUsername(oldDisplayName, newDisplayName, username) | ||
52 | this.form.patchValue({ username: newUsername }) | ||
53 | } | ||
54 | } | ||
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..d7e47c1a8 --- /dev/null +++ b/client/src/app/+signup/+register/register.component.html | |||
@@ -0,0 +1,47 @@ | |||
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="!signupDone && !error" class="done-loader"> | ||
31 | <my-loader [loading]="true"></my-loader> | ||
32 | |||
33 | <div i18n>PeerTube is creating your account...</div> | ||
34 | </div> | ||
35 | |||
36 | <div *ngIf="error" class="alert alert-danger">{{ error }}</div> | ||
37 | </cdk-step> | ||
38 | </my-custom-stepper> | ||
39 | </div> | ||
40 | |||
41 | <div> | ||
42 | <label i18n>Features found on this instance</label> | ||
43 | <my-instance-features-table></my-instance-features-table> | ||
44 | </div> | ||
45 | </div> | ||
46 | |||
47 | </div> | ||
diff --git a/client/src/app/+signup/+register/register.component.scss b/client/src/app/+signup/+register/register.component.scss new file mode 100644 index 000000000..8d14992e7 --- /dev/null +++ b/client/src/app/+signup/+register/register.component.scss | |||
@@ -0,0 +1,81 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
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 | |||
24 | my-instance-features-table { | ||
25 | display: block; | ||
26 | |||
27 | margin-bottom: 40px; | ||
28 | } | ||
29 | |||
30 | .form-group-terms { | ||
31 | margin: 30px 0; | ||
32 | } | ||
33 | |||
34 | .input-group { | ||
35 | @include peertube-input-group(400px); | ||
36 | } | ||
37 | |||
38 | .input-group-append { | ||
39 | height: 30px; | ||
40 | } | ||
41 | |||
42 | input:not([type=submit]) { | ||
43 | @include peertube-input-text(400px); | ||
44 | |||
45 | display: block; | ||
46 | |||
47 | &#username, | ||
48 | &#name { | ||
49 | width: auto !important; | ||
50 | flex-grow: 1; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | input[type=submit], | ||
55 | button { | ||
56 | @include peertube-button; | ||
57 | @include orange-button; | ||
58 | } | ||
59 | |||
60 | .name-information { | ||
61 | margin-top: 10px; | ||
62 | } | ||
63 | |||
64 | .done-loader { | ||
65 | display: flex; | ||
66 | justify-content: center; | ||
67 | flex-direction: column; | ||
68 | align-items: center; | ||
69 | |||
70 | my-loader { | ||
71 | margin-bottom: 20px; | ||
72 | |||
73 | /deep/ .loader div { | ||
74 | border-color: var(--mainColor) transparent transparent transparent; | ||
75 | } | ||
76 | |||
77 | & + div { | ||
78 | font-size: 15px; | ||
79 | } | ||
80 | } | ||
81 | } | ||
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 @@ | |||
1 | import { Component } from '@angular/core' | ||
2 | import { AuthService, Notifier, RedirectService, ServerService } from '@app/core' | ||
3 | import { UserService, UserValidatorsService } from '@app/shared' | ||
4 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
5 | import { UserRegister } from '@shared/models/users/user-register.model' | ||
6 | import { FormGroup } from '@angular/forms' | ||
7 | |||
8 | @Component({ | ||
9 | selector: 'my-register', | ||
10 | templateUrl: './register.component.html', | ||
11 | styleUrls: [ './register.component.scss' ] | ||
12 | }) | ||
13 | export 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 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | import { RegisterRoutingModule } from './register-routing.module' | ||
3 | import { RegisterComponent } from './register.component' | ||
4 | import { SharedModule } from '@app/shared' | ||
5 | import { CdkStepperModule } from '@angular/cdk/stepper' | ||
6 | import { RegisterStepChannelComponent } from './register-step-channel.component' | ||
7 | import { RegisterStepUserComponent } from './register-step-user.component' | ||
8 | import { CustomStepperComponent } from './custom-stepper.component' | ||
9 | import { 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 | }) | ||
33 | export 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/+signup/+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 new file mode 100644 index 000000000..47519c943 --- /dev/null +++ b/client/src/app/+signup/+verify-account/verify-account-email/verify-account-email.component.html | |||
@@ -0,0 +1,18 @@ | |||
1 | <div class="margin-content"> | ||
2 | <div i18n class="title-page title-page-single"> | ||
3 | Verify account email confirmation | ||
4 | </div> | ||
5 | |||
6 | <my-signup-success i18n *ngIf="!isPendingEmail && success" message="Your email has been verified and you may now login."> | ||
7 | </my-signup-success> | ||
8 | |||
9 | <div i18n class="alert alert-success" *ngIf="isPendingEmail && success"> | ||
10 | Email updated. | ||
11 | </div> | ||
12 | |||
13 | <div *ngIf="failed"> | ||
14 | <span i18n>An error occurred.</span> | ||
15 | |||
16 | <a i18n routerLink="/verify-account/ask-send-email" [queryParams]="{ isPendingEmail: isPendingEmail }">Request new verification email.</a> | ||
17 | </div> | ||
18 | </div> | ||
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..054f04310 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 | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | 1 | import { Component, OnInit } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router' | 2 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | 3 | import { I18n } from '@ngx-translate/i18n-polyfill' |
4 | import { Notifier } from '@app/core' | 4 | import { AuthService, Notifier } from '@app/core' |
5 | import { UserService } from '@app/shared' | 5 | import { UserService } from '@app/shared' |
6 | 6 | ||
7 | @Component({ | 7 | @Component({ |
@@ -11,12 +11,15 @@ import { UserService } from '@app/shared' | |||
11 | 11 | ||
12 | export class VerifyAccountEmailComponent implements OnInit { | 12 | export class VerifyAccountEmailComponent implements OnInit { |
13 | success = false | 13 | success = false |
14 | failed = false | ||
15 | isPendingEmail = false | ||
14 | 16 | ||
15 | private userId: number | 17 | private userId: number |
16 | private verificationString: string | 18 | private verificationString: string |
17 | 19 | ||
18 | constructor ( | 20 | constructor ( |
19 | private userService: UserService, | 21 | private userService: UserService, |
22 | private authService: AuthService, | ||
20 | private notifier: Notifier, | 23 | private notifier: Notifier, |
21 | private router: Router, | 24 | private router: Router, |
22 | private route: ActivatedRoute, | 25 | private route: ActivatedRoute, |
@@ -25,8 +28,12 @@ export class VerifyAccountEmailComponent implements OnInit { | |||
25 | } | 28 | } |
26 | 29 | ||
27 | ngOnInit () { | 30 | ngOnInit () { |
28 | this.userId = this.route.snapshot.queryParams['userId'] | 31 | const queryParams = this.route.snapshot.queryParams |
29 | this.verificationString = this.route.snapshot.queryParams['verificationString'] | 32 | this.userId = queryParams['userId'] |
33 | this.verificationString = queryParams['verificationString'] | ||
34 | this.isPendingEmail = queryParams['isPendingEmail'] === 'true' | ||
35 | |||
36 | console.log(this.isPendingEmail) | ||
30 | 37 | ||
31 | if (!this.userId || !this.verificationString) { | 38 | if (!this.userId || !this.verificationString) { |
32 | this.notifier.error(this.i18n('Unable to find user id or verification string.')) | 39 | this.notifier.error(this.i18n('Unable to find user id or verification string.')) |
@@ -36,16 +43,17 @@ export class VerifyAccountEmailComponent implements OnInit { | |||
36 | } | 43 | } |
37 | 44 | ||
38 | verifyEmail () { | 45 | verifyEmail () { |
39 | this.userService.verifyEmail(this.userId, this.verificationString) | 46 | this.userService.verifyEmail(this.userId, this.verificationString, this.isPendingEmail) |
40 | .subscribe( | 47 | .subscribe( |
41 | () => { | 48 | () => { |
49 | this.authService.refreshUserInformation() | ||
50 | |||
42 | this.success = true | 51 | this.success = true |
43 | setTimeout(() => { | ||
44 | this.router.navigate([ '/login' ]) | ||
45 | }, 2000) | ||
46 | }, | 52 | }, |
47 | 53 | ||
48 | err => { | 54 | err => { |
55 | this.failed = true | ||
56 | |||
49 | this.notifier.error(err.message) | 57 | this.notifier.error(err.message) |
50 | } | 58 | } |
51 | ) | 59 | ) |
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 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router' | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | |||
4 | import { MetaGuard } from '@ngx-meta/core' | 3 | import { MetaGuard } from '@ngx-meta/core' |
5 | 4 | import { VerifyAccountEmailComponent } from './verify-account-email/verify-account-email.component' | |
6 | import { VerifyAccountEmailComponent } from '@app/+verify-account/verify-account-email/verify-account-email.component' | 5 | import { VerifyAccountAskSendEmailComponent } from './verify-account-ask-send-email/verify-account-ask-send-email.component' |
7 | import { | ||
8 | VerifyAccountAskSendEmailComponent | ||
9 | } from '@app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component' | ||
10 | 6 | ||
11 | const verifyAccountRoutes: Routes = [ | 7 | const 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 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | import { VerifyAccountRoutingModule } from './verify-account-routing.module' | ||
3 | import { VerifyAccountEmailComponent } from './verify-account-email/verify-account-email.component' | ||
4 | import { VerifyAccountAskSendEmailComponent } from './verify-account-ask-send-email/verify-account-ask-send-email.component' | ||
5 | import { SharedModule } from '@app/shared' | ||
6 | import { 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 | }) | ||
24 | export 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 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | import { SignupSuccessComponent } from '../shared/signup-success.component' | ||
3 | import { 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 | }) | ||
21 | export 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 @@ | |||
1 | svg { | ||
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 @@ | |||
1 | import { 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 | }) | ||
8 | export 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 @@ | |||
1 | export * from '@app/+verify-account/verify-account-routing.module' | ||
2 | export * from '@app/+verify-account/verify-account.module' | ||
diff --git a/client/src/app/+verify-account/verify-account-email/verify-account-email.component.html b/client/src/app/+verify-account/verify-account-email/verify-account-email.component.html deleted file mode 100644 index a83d4a3c2..000000000 --- a/client/src/app/+verify-account/verify-account-email/verify-account-email.component.html +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | <div class="margin-content"> | ||
2 | <div i18n class="title-page title-page-single"> | ||
3 | Verify account email confirmation | ||
4 | </div> | ||
5 | |||
6 | <div i18n *ngIf="success; else verificationError"> | ||
7 | Your email has been verified and you may now login. Redirecting... | ||
8 | </div> | ||
9 | <ng-template #verificationError> | ||
10 | <div> | ||
11 | <span i18n>An error occurred. </span> | ||
12 | <a i18n routerLink="/verify-account/ask-send-email">Request new verification email.</a> | ||
13 | </div> | ||
14 | </ng-template> | ||
15 | </div> | ||
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 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | |||
3 | import { VerifyAccountRoutingModule } from '@app/+verify-account/verify-account-routing.module' | ||
4 | import { VerifyAccountEmailComponent } from '@app/+verify-account/verify-account-email/verify-account-email.component' | ||
5 | import { | ||
6 | VerifyAccountAskSendEmailComponent | ||
7 | } from '@app/+verify-account/verify-account-ask-send-email/verify-account-ask-send-email.component' | ||
8 | import { 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 | }) | ||
27 | export 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' | |||
5 | import { Subscription } from 'rxjs' | 5 | import { Subscription } from 'rxjs' |
6 | import { Notifier } from '@app/core' | 6 | import { Notifier } from '@app/core' |
7 | import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' | 7 | import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' |
8 | import { ComponentPagination } from '@app/shared/rest/component-pagination.model' | 8 | import { ComponentPagination, hasMoreItems } from '@app/shared/rest/component-pagination.model' |
9 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' | 9 | import { 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' | |||
14 | import { LoginModule } from './login' | 14 | import { LoginModule } from './login' |
15 | import { AvatarNotificationComponent, LanguageChooserComponent, MenuComponent } from './menu' | 15 | import { AvatarNotificationComponent, LanguageChooserComponent, MenuComponent } from './menu' |
16 | import { SharedModule } from './shared' | 16 | import { SharedModule } from './shared' |
17 | import { SignupModule } from './signup' | ||
18 | import { VideosModule } from './videos' | 17 | import { VideosModule } from './videos' |
19 | import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '../../../shared/models/i18n' | 18 | import { buildFileLocale, getCompleteLocale, isDefaultLocale } from '../../../shared/models/i18n' |
20 | import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' | 19 | import { 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' | |||
20 | import { MessageService } from 'primeng/api' | 20 | import { MessageService } from 'primeng/api' |
21 | import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service' | 21 | import { UserNotificationSocket } from '@app/core/notification/user-notification-socket.service' |
22 | import { ServerConfigResolver } from './routing/server-config-resolver.service' | 22 | import { ServerConfigResolver } from './routing/server-config-resolver.service' |
23 | import { 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 @@ | |||
1 | import { Injectable } from '@angular/core' | ||
2 | import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, Router, RouterStateSnapshot } from '@angular/router' | ||
3 | import { AuthService } from '../auth/auth.service' | ||
4 | import { RedirectService } from './redirect.service' | ||
5 | |||
6 | @Injectable() | ||
7 | export 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/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index 3a8a535fd..689f25a40 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts | |||
@@ -10,6 +10,7 @@ import { isDefaultLocale, peertubeTranslate } from '../../../../../shared/models | |||
10 | import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' | 10 | import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' |
11 | import { sortBy } from '@app/shared/misc/utils' | 11 | import { sortBy } from '@app/shared/misc/utils' |
12 | import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model' | 12 | import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model' |
13 | import { cloneDeep } from 'lodash-es' | ||
13 | 14 | ||
14 | @Injectable() | 15 | @Injectable() |
15 | export class ServerService { | 16 | export class ServerService { |
@@ -160,27 +161,27 @@ export class ServerService { | |||
160 | } | 161 | } |
161 | 162 | ||
162 | getConfig () { | 163 | getConfig () { |
163 | return this.config | 164 | return cloneDeep(this.config) |
164 | } | 165 | } |
165 | 166 | ||
166 | getVideoCategories () { | 167 | getVideoCategories () { |
167 | return this.videoCategories | 168 | return cloneDeep(this.videoCategories) |
168 | } | 169 | } |
169 | 170 | ||
170 | getVideoLicences () { | 171 | getVideoLicences () { |
171 | return this.videoLicences | 172 | return cloneDeep(this.videoLicences) |
172 | } | 173 | } |
173 | 174 | ||
174 | getVideoLanguages () { | 175 | getVideoLanguages () { |
175 | return this.videoLanguages | 176 | return cloneDeep(this.videoLanguages) |
176 | } | 177 | } |
177 | 178 | ||
178 | getVideoPrivacies () { | 179 | getVideoPrivacies () { |
179 | return this.videoPrivacies | 180 | return cloneDeep(this.videoPrivacies) |
180 | } | 181 | } |
181 | 182 | ||
182 | getVideoPlaylistPrivacies () { | 183 | getVideoPlaylistPrivacies () { |
183 | return this.videoPlaylistPrivacies | 184 | return cloneDeep(this.videoPlaylistPrivacies) |
184 | } | 185 | } |
185 | 186 | ||
186 | private loadAttributeEnum ( | 187 | private loadAttributeEnum ( |
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html index e80e6b803..588cb8548 100644 --- a/client/src/app/menu/menu.component.html +++ b/client/src/app/menu/menu.component.html | |||
@@ -63,7 +63,7 @@ | |||
63 | 63 | ||
64 | <a routerLink="/videos/overview" routerLinkActive="active"> | 64 | <a routerLink="/videos/overview" routerLinkActive="active"> |
65 | <my-global-icon iconName="globe"></my-global-icon> | 65 | <my-global-icon iconName="globe"></my-global-icon> |
66 | <ng-container i18n>Overview</ng-container> | 66 | <ng-container i18n>Discover</ng-container> |
67 | </a> | 67 | </a> |
68 | 68 | ||
69 | <a routerLink="/videos/trending" routerLinkActive="active"> | 69 | <a routerLink="/videos/trending" routerLinkActive="active"> |
diff --git a/client/src/app/search/search.component.html b/client/src/app/search/search.component.html index 0a9f78cb2..055f64cc8 100644 --- a/client/src/app/search/search.component.html +++ b/client/src/app/search/search.component.html | |||
@@ -20,7 +20,7 @@ | |||
20 | </div> | 20 | </div> |
21 | </div> | 21 | </div> |
22 | 22 | ||
23 | <div class="results-filter" [ngbCollapse]="isSearchFilterCollapsed"> | 23 | <div class="results-filter collapse-transition" [ngbCollapse]="isSearchFilterCollapsed"> |
24 | <my-search-filters [advancedSearch]="advancedSearch" (filtered)="onFiltered()"></my-search-filters> | 24 | <my-search-filters [advancedSearch]="advancedSearch" (filtered)="onFiltered()"></my-search-filters> |
25 | </div> | 25 | </div> |
26 | </div> | 26 | </div> |
diff --git a/client/src/app/search/search.component.scss b/client/src/app/search/search.component.scss index 4e3ce1c96..3343a276d 100644 --- a/client/src/app/search/search.component.scss +++ b/client/src/app/search/search.component.scss | |||
@@ -35,18 +35,6 @@ | |||
35 | } | 35 | } |
36 | } | 36 | } |
37 | } | 37 | } |
38 | |||
39 | .results-filter { | ||
40 | // Animation when we show/hide the filters | ||
41 | transition: max-height 0.3s; | ||
42 | display: block !important; | ||
43 | overflow: hidden !important; | ||
44 | max-height: 0; | ||
45 | |||
46 | &.show { | ||
47 | max-height: 1500px; | ||
48 | } | ||
49 | } | ||
50 | } | 38 | } |
51 | 39 | ||
52 | .entry { | 40 | .entry { |
diff --git a/client/src/app/search/search.module.ts b/client/src/app/search/search.module.ts index 0411fbe24..8b791621e 100644 --- a/client/src/app/search/search.module.ts +++ b/client/src/app/search/search.module.ts | |||
@@ -4,14 +4,11 @@ import { SearchComponent } from '@app/search/search.component' | |||
4 | import { SearchService } from '@app/search/search.service' | 4 | import { SearchService } from '@app/search/search.service' |
5 | import { SearchRoutingModule } from '@app/search/search-routing.module' | 5 | import { SearchRoutingModule } from '@app/search/search-routing.module' |
6 | import { SearchFiltersComponent } from '@app/search/search-filters.component' | 6 | import { SearchFiltersComponent } from '@app/search/search-filters.component' |
7 | import { NgbCollapseModule } from '@ng-bootstrap/ng-bootstrap' | ||
8 | 7 | ||
9 | @NgModule({ | 8 | @NgModule({ |
10 | imports: [ | 9 | imports: [ |
11 | SearchRoutingModule, | 10 | SearchRoutingModule, |
12 | SharedModule, | 11 | SharedModule |
13 | |||
14 | NgbCollapseModule | ||
15 | ], | 12 | ], |
16 | 13 | ||
17 | declarations: [ | 14 | declarations: [ |
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 | ||
5 | export abstract class Actor implements ActorServer { | 5 | export 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 | ||
10 | export class ButtonComponent { | 10 | export 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/form-validators/user-validators.service.ts b/client/src/app/shared/forms/form-validators/user-validators.service.ts index 6589b2580..2dafb1816 100644 --- a/client/src/app/shared/forms/form-validators/user-validators.service.ts +++ b/client/src/app/shared/forms/form-validators/user-validators.service.ts | |||
@@ -12,7 +12,7 @@ export class UserValidatorsService { | |||
12 | readonly USER_VIDEO_QUOTA: BuildFormValidator | 12 | readonly USER_VIDEO_QUOTA: BuildFormValidator |
13 | readonly USER_VIDEO_QUOTA_DAILY: BuildFormValidator | 13 | readonly USER_VIDEO_QUOTA_DAILY: BuildFormValidator |
14 | readonly USER_ROLE: BuildFormValidator | 14 | readonly USER_ROLE: BuildFormValidator |
15 | readonly USER_DISPLAY_NAME: BuildFormValidator | 15 | readonly USER_DISPLAY_NAME_REQUIRED: BuildFormValidator |
16 | readonly USER_DESCRIPTION: BuildFormValidator | 16 | readonly USER_DESCRIPTION: BuildFormValidator |
17 | readonly USER_TERMS: BuildFormValidator | 17 | readonly USER_TERMS: BuildFormValidator |
18 | 18 | ||
@@ -85,18 +85,7 @@ export class UserValidatorsService { | |||
85 | } | 85 | } |
86 | } | 86 | } |
87 | 87 | ||
88 | this.USER_DISPLAY_NAME = { | 88 | this.USER_DISPLAY_NAME_REQUIRED = this.getDisplayName(true) |
89 | VALIDATORS: [ | ||
90 | Validators.required, | ||
91 | Validators.minLength(1), | ||
92 | Validators.maxLength(50) | ||
93 | ], | ||
94 | MESSAGES: { | ||
95 | 'required': this.i18n('Display name is required.'), | ||
96 | 'minlength': this.i18n('Display name must be at least 1 character long.'), | ||
97 | 'maxlength': this.i18n('Display name cannot be more than 50 characters long.') | ||
98 | } | ||
99 | } | ||
100 | 89 | ||
101 | this.USER_DESCRIPTION = { | 90 | this.USER_DESCRIPTION = { |
102 | VALIDATORS: [ | 91 | VALIDATORS: [ |
@@ -129,4 +118,22 @@ export class UserValidatorsService { | |||
129 | } | 118 | } |
130 | } | 119 | } |
131 | } | 120 | } |
121 | |||
122 | private getDisplayName (required: boolean) { | ||
123 | const control = { | ||
124 | VALIDATORS: [ | ||
125 | Validators.minLength(1), | ||
126 | Validators.maxLength(120) | ||
127 | ], | ||
128 | MESSAGES: { | ||
129 | 'required': this.i18n('Display name is required.'), | ||
130 | 'minlength': this.i18n('Display name must be at least 1 character long.'), | ||
131 | 'maxlength': this.i18n('Display name cannot be more than 50 characters long.') | ||
132 | } | ||
133 | } | ||
134 | |||
135 | if (required) control.VALIDATORS.push(Validators.required) | ||
136 | |||
137 | return control | ||
138 | } | ||
132 | } | 139 | } |
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 | |||
2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' | 2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' |
3 | import { Notifier } from '@app/core' | 3 | import { Notifier } from '@app/core' |
4 | import { I18n } from '@ngx-translate/i18n-polyfill' | 4 | import { I18n } from '@ngx-translate/i18n-polyfill' |
5 | import { 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 @@ | |||
1 | import { Component, forwardRef, Input } from '@angular/core' | 1 | import { Component, forwardRef, Input, OnInit } from '@angular/core' |
2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' | 2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms' |
3 | import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser' | 3 | import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser' |
4 | import { ServerService } from '@app/core' | 4 | import { 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 | }) |
18 | export class ImageUploadComponent implements ControlValueAccessor { | 18 | export 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' | |||
3 | import { Injectable } from '@angular/core' | 3 | import { Injectable } from '@angular/core' |
4 | import { SortMeta } from 'primeng/primeng' | 4 | import { SortMeta } from 'primeng/primeng' |
5 | import { Observable } from 'rxjs' | 5 | import { Observable } from 'rxjs' |
6 | import { ActorFollow, ResultList } from '../../../../../../shared' | 6 | import { ActorFollow, ResultList } from '@shared/index' |
7 | import { environment } from '../../../../environments/environment' | 7 | import { environment } from '../../../environments/environment' |
8 | import { RestExtractor, RestPagination, RestService } from '../../../shared' | 8 | import { RestExtractor, RestPagination, RestService } from '../rest' |
9 | 9 | ||
10 | @Injectable() | 10 | @Injectable() |
11 | export class FollowService { | 11 | export 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/misc/loader.component.html b/client/src/app/shared/misc/loader.component.html index b8b7ad343..ca8ed063e 100644 --- a/client/src/app/shared/misc/loader.component.html +++ b/client/src/app/shared/misc/loader.component.html | |||
@@ -1,5 +1,5 @@ | |||
1 | <div *ngIf="loading"> | 1 | <div *ngIf="loading"> |
2 | <div class="lds-ring"> | 2 | <div class="loader"> |
3 | <div></div> | 3 | <div></div> |
4 | <div></div> | 4 | <div></div> |
5 | <div></div> | 5 | <div></div> |
diff --git a/client/src/app/shared/misc/loader.component.scss b/client/src/app/shared/misc/loader.component.scss index ddb64f07a..ffac9c707 100644 --- a/client/src/app/shared/misc/loader.component.scss +++ b/client/src/app/shared/misc/loader.component.scss | |||
@@ -3,14 +3,14 @@ | |||
3 | 3 | ||
4 | // Thanks to https://loading.io/css/ (CC0 License) | 4 | // Thanks to https://loading.io/css/ (CC0 License) |
5 | 5 | ||
6 | .lds-ring { | 6 | .loader { |
7 | display: inline-block; | 7 | display: inline-block; |
8 | position: relative; | 8 | position: relative; |
9 | width: 50px; | 9 | width: 50px; |
10 | height: 50px; | 10 | height: 50px; |
11 | } | 11 | } |
12 | 12 | ||
13 | .lds-ring div { | 13 | .loader div { |
14 | box-sizing: border-box; | 14 | box-sizing: border-box; |
15 | display: block; | 15 | display: block; |
16 | position: absolute; | 16 | position: absolute; |
@@ -19,23 +19,23 @@ | |||
19 | margin: 6px; | 19 | margin: 6px; |
20 | border: 4px solid; | 20 | border: 4px solid; |
21 | border-radius: 50%; | 21 | border-radius: 50%; |
22 | animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; | 22 | animation: loader 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; |
23 | border-color: #999999 transparent transparent transparent; | 23 | border-color: #999999 transparent transparent transparent; |
24 | } | 24 | } |
25 | 25 | ||
26 | .lds-ring div:nth-child(1) { | 26 | .loader div:nth-child(1) { |
27 | animation-delay: -0.45s; | 27 | animation-delay: -0.45s; |
28 | } | 28 | } |
29 | 29 | ||
30 | .lds-ring div:nth-child(2) { | 30 | .loader div:nth-child(2) { |
31 | animation-delay: -0.3s; | 31 | animation-delay: -0.3s; |
32 | } | 32 | } |
33 | 33 | ||
34 | .lds-ring div:nth-child(3) { | 34 | .loader div:nth-child(3) { |
35 | animation-delay: -0.15s; | 35 | animation-delay: -0.15s; |
36 | } | 36 | } |
37 | 37 | ||
38 | @keyframes lds-ring { | 38 | @keyframes loader { |
39 | 0% { | 39 | 0% { |
40 | transform: rotate(0deg); | 40 | transform: rotate(0deg); |
41 | } | 41 | } |
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index ded65653f..eb57a2fff 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts | |||
@@ -53,7 +53,14 @@ import { VideoCaptionService } from '@app/shared/video-caption' | |||
53 | import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.component' | 53 | import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.component' |
54 | import { VideoImportService } from '@app/shared/video-import/video-import.service' | 54 | import { VideoImportService } from '@app/shared/video-import/video-import.service' |
55 | import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component' | 55 | import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component' |
56 | import { NgbDropdownModule, NgbModalModule, NgbPopoverModule, NgbTabsetModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap' | 56 | import { |
57 | NgbCollapseModule, | ||
58 | NgbDropdownModule, | ||
59 | NgbModalModule, | ||
60 | NgbPopoverModule, | ||
61 | NgbTabsetModule, | ||
62 | NgbTooltipModule | ||
63 | } from '@ng-bootstrap/ng-bootstrap' | ||
57 | import { RemoteSubscribeComponent, SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription' | 64 | import { RemoteSubscribeComponent, SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription' |
58 | import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component' | 65 | import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component' |
59 | import { OverviewService } from '@app/shared/overview' | 66 | import { OverviewService } from '@app/shared/overview' |
@@ -69,7 +76,7 @@ import { HtmlRendererService, LinkifierService, MarkdownService } from '@app/sha | |||
69 | import { ConfirmComponent } from '@app/shared/confirm/confirm.component' | 76 | import { ConfirmComponent } from '@app/shared/confirm/confirm.component' |
70 | import { SmallLoaderComponent } from '@app/shared/misc/small-loader.component' | 77 | import { SmallLoaderComponent } from '@app/shared/misc/small-loader.component' |
71 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' | 78 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' |
72 | import { ImageUploadComponent } from '@app/shared/images/image-upload.component' | 79 | import { PreviewUploadComponent } from '@app/shared/images/preview-upload.component' |
73 | import { GlobalIconComponent } from '@app/shared/images/global-icon.component' | 80 | import { GlobalIconComponent } from '@app/shared/images/global-icon.component' |
74 | import { VideoPlaylistMiniatureComponent } from '@app/shared/video-playlist/video-playlist-miniature.component' | 81 | import { VideoPlaylistMiniatureComponent } from '@app/shared/video-playlist/video-playlist-miniature.component' |
75 | import { VideoAddToPlaylistComponent } from '@app/shared/video-playlist/video-add-to-playlist.component' | 82 | import { VideoAddToPlaylistComponent } from '@app/shared/video-playlist/video-add-to-playlist.component' |
@@ -85,6 +92,7 @@ import { VideoBlacklistComponent } from '@app/shared/video/modals/video-blacklis | |||
85 | import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component' | 92 | import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component' |
86 | import { VideoReportComponent } from '@app/shared/video/modals/video-report.component' | 93 | import { VideoReportComponent } from '@app/shared/video/modals/video-report.component' |
87 | import { ClipboardModule } from 'ngx-clipboard' | 94 | import { ClipboardModule } from 'ngx-clipboard' |
95 | import { FollowService } from '@app/shared/instance/follow.service' | ||
88 | 96 | ||
89 | @NgModule({ | 97 | @NgModule({ |
90 | imports: [ | 98 | imports: [ |
@@ -99,6 +107,7 @@ import { ClipboardModule } from 'ngx-clipboard' | |||
99 | NgbPopoverModule, | 107 | NgbPopoverModule, |
100 | NgbTabsetModule, | 108 | NgbTabsetModule, |
101 | NgbTooltipModule, | 109 | NgbTooltipModule, |
110 | NgbCollapseModule, | ||
102 | 111 | ||
103 | ClipboardModule, | 112 | ClipboardModule, |
104 | 113 | ||
@@ -154,7 +163,7 @@ import { ClipboardModule } from 'ngx-clipboard' | |||
154 | ConfirmComponent, | 163 | ConfirmComponent, |
155 | 164 | ||
156 | GlobalIconComponent, | 165 | GlobalIconComponent, |
157 | ImageUploadComponent | 166 | PreviewUploadComponent |
158 | ], | 167 | ], |
159 | 168 | ||
160 | exports: [ | 169 | exports: [ |
@@ -169,6 +178,7 @@ import { ClipboardModule } from 'ngx-clipboard' | |||
169 | NgbPopoverModule, | 178 | NgbPopoverModule, |
170 | NgbTabsetModule, | 179 | NgbTabsetModule, |
171 | NgbTooltipModule, | 180 | NgbTooltipModule, |
181 | NgbCollapseModule, | ||
172 | 182 | ||
173 | ClipboardModule, | 183 | ClipboardModule, |
174 | 184 | ||
@@ -218,7 +228,7 @@ import { ClipboardModule } from 'ngx-clipboard' | |||
218 | ConfirmComponent, | 228 | ConfirmComponent, |
219 | 229 | ||
220 | GlobalIconComponent, | 230 | GlobalIconComponent, |
221 | ImageUploadComponent, | 231 | PreviewUploadComponent, |
222 | 232 | ||
223 | NumberFormatterPipe, | 233 | NumberFormatterPipe, |
224 | ObjectLengthPipe, | 234 | ObjectLengthPipe, |
@@ -271,6 +281,8 @@ import { ClipboardModule } from 'ngx-clipboard' | |||
271 | 281 | ||
272 | UserNotificationService, | 282 | UserNotificationService, |
273 | 283 | ||
284 | FollowService, | ||
285 | |||
274 | I18n | 286 | I18n |
275 | ] | 287 | ] |
276 | }) | 288 | }) |
diff --git a/client/src/app/shared/users/user-notifications.component.scss b/client/src/app/shared/users/user-notifications.component.scss index 88f38d9cf..0c6c70d98 100644 --- a/client/src/app/shared/users/user-notifications.component.scss +++ b/client/src/app/shared/users/user-notifications.component.scss | |||
@@ -14,6 +14,7 @@ | |||
14 | font-size: inherit; | 14 | font-size: inherit; |
15 | padding: 15px 5px 15px 10px; | 15 | padding: 15px 5px 15px 10px; |
16 | border-bottom: 1px solid $separator-border-color; | 16 | border-bottom: 1px solid $separator-border-color; |
17 | word-break: break-word; | ||
17 | 18 | ||
18 | &.unread { | 19 | &.unread { |
19 | background-color: rgba(0, 0, 0, 0.05); | 20 | background-color: rgba(0, 0, 0, 0.05); |
diff --git a/client/src/app/shared/users/user.model.ts b/client/src/app/shared/users/user.model.ts index e3ed2dfbd..14d13959a 100644 --- a/client/src/app/shared/users/user.model.ts +++ b/client/src/app/shared/users/user.model.ts | |||
@@ -8,6 +8,7 @@ export class User implements UserServerModel { | |||
8 | id: number | 8 | id: number |
9 | username: string | 9 | username: string |
10 | email: string | 10 | email: string |
11 | pendingEmail: string | null | ||
11 | emailVerified: boolean | 12 | emailVerified: boolean |
12 | nsfwPolicy: NSFWPolicyType | 13 | nsfwPolicy: NSFWPolicyType |
13 | 14 | ||
diff --git a/client/src/app/shared/users/user.service.ts b/client/src/app/shared/users/user.service.ts index cc5c051f1..41ee87197 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' | |||
9 | import { SortMeta } from 'primeng/api' | 9 | import { SortMeta } from 'primeng/api' |
10 | import { BytesPipe } from 'ngx-pipes' | 10 | import { BytesPipe } from 'ngx-pipes' |
11 | import { I18n } from '@ngx-translate/i18n-polyfill' | 11 | import { I18n } from '@ngx-translate/i18n-polyfill' |
12 | import { UserRegister } from '@shared/models/users/user-register.model' | ||
12 | 13 | ||
13 | @Injectable() | 14 | @Injectable() |
14 | export class UserService { | 15 | export class UserService { |
@@ -37,6 +38,20 @@ export class UserService { | |||
37 | ) | 38 | ) |
38 | } | 39 | } |
39 | 40 | ||
41 | changeEmail (password: string, newEmail: string) { | ||
42 | const url = UserService.BASE_USERS_URL + 'me' | ||
43 | const body: UserUpdateMe = { | ||
44 | currentPassword: password, | ||
45 | email: newEmail | ||
46 | } | ||
47 | |||
48 | return this.authHttp.put(url, body) | ||
49 | .pipe( | ||
50 | map(this.restExtractor.extractDataBool), | ||
51 | catchError(err => this.restExtractor.handleError(err)) | ||
52 | ) | ||
53 | } | ||
54 | |||
40 | updateMyProfile (profile: UserUpdateMe) { | 55 | updateMyProfile (profile: UserUpdateMe) { |
41 | const url = UserService.BASE_USERS_URL + 'me' | 56 | const url = UserService.BASE_USERS_URL + 'me' |
42 | 57 | ||
@@ -64,7 +79,7 @@ export class UserService { | |||
64 | .pipe(catchError(err => this.restExtractor.handleError(err))) | 79 | .pipe(catchError(err => this.restExtractor.handleError(err))) |
65 | } | 80 | } |
66 | 81 | ||
67 | signup (userCreate: UserCreate) { | 82 | signup (userCreate: UserRegister) { |
68 | return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate) | 83 | return this.authHttp.post(UserService.BASE_USERS_URL + 'register', userCreate) |
69 | .pipe( | 84 | .pipe( |
70 | map(this.restExtractor.extractDataBool), | 85 | map(this.restExtractor.extractDataBool), |
@@ -103,10 +118,11 @@ export class UserService { | |||
103 | ) | 118 | ) |
104 | } | 119 | } |
105 | 120 | ||
106 | verifyEmail (userId: number, verificationString: string) { | 121 | verifyEmail (userId: number, verificationString: string, isPendingEmail: boolean) { |
107 | const url = `${UserService.BASE_USERS_URL}/${userId}/verify-email` | 122 | const url = `${UserService.BASE_USERS_URL}/${userId}/verify-email` |
108 | const body = { | 123 | const body = { |
109 | verificationString | 124 | verificationString, |
125 | isPendingEmail | ||
110 | } | 126 | } |
111 | 127 | ||
112 | return this.authHttp.post(url, body) | 128 | return this.authHttp.post(url, body) |
@@ -135,6 +151,22 @@ export class UserService { | |||
135 | .pipe(catchError(res => this.restExtractor.handleError(res))) | 151 | .pipe(catchError(res => this.restExtractor.handleError(res))) |
136 | } | 152 | } |
137 | 153 | ||
154 | getNewUsername (oldDisplayName: string, newDisplayName: string, currentUsername: string) { | ||
155 | // Don't update display name, the user seems to have changed it | ||
156 | if (this.displayNameToUsername(oldDisplayName) !== currentUsername) return currentUsername | ||
157 | |||
158 | return this.displayNameToUsername(newDisplayName) | ||
159 | } | ||
160 | |||
161 | displayNameToUsername (displayName: string) { | ||
162 | if (!displayName) return '' | ||
163 | |||
164 | return displayName | ||
165 | .toLowerCase() | ||
166 | .replace(/\s/g, '_') | ||
167 | .replace(/[^a-z0-9_.]/g, '') | ||
168 | } | ||
169 | |||
138 | /* ###### Admin methods ###### */ | 170 | /* ###### Admin methods ###### */ |
139 | 171 | ||
140 | addUser (userCreate: UserCreate) { | 172 | addUser (userCreate: UserCreate) { |
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' | |||
2 | import { Injectable } from '@angular/core' | 2 | import { Injectable } from '@angular/core' |
3 | import { Observable, ReplaySubject } from 'rxjs' | 3 | import { Observable, ReplaySubject } from 'rxjs' |
4 | import { RestExtractor } from '../rest/rest-extractor.service' | 4 | import { RestExtractor } from '../rest/rest-extractor.service' |
5 | import { HttpClient } from '@angular/common/http' | 5 | import { HttpClient, HttpParams } from '@angular/common/http' |
6 | import { VideoChannel as VideoChannelServer, VideoChannelCreate, VideoChannelUpdate } from '../../../../../shared/models/videos' | 6 | import { VideoChannel as VideoChannelServer, VideoChannelCreate, VideoChannelUpdate } from '../../../../../shared/models/videos' |
7 | import { AccountService } from '../account/account.service' | 7 | import { AccountService } from '../account/account.service' |
8 | import { ResultList } from '../../../../../shared' | 8 | import { ResultList } from '../../../../../shared' |
@@ -10,6 +10,8 @@ import { VideoChannel } from './video-channel.model' | |||
10 | import { environment } from '../../../environments/environment' | 10 | import { environment } from '../../../environments/environment' |
11 | import { Account } from '@app/shared/account/account.model' | 11 | import { Account } from '@app/shared/account/account.model' |
12 | import { Avatar } from '../../../../../shared/models/avatars/avatar.model' | 12 | import { Avatar } from '../../../../../shared/models/avatars/avatar.model' |
13 | import { ComponentPagination } from '@app/shared/rest/component-pagination.model' | ||
14 | import { RestService } from '@app/shared/rest' | ||
13 | 15 | ||
14 | @Injectable() | 16 | @Injectable() |
15 | export class VideoChannelService { | 17 | export 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 | |||
11 | import { Syndication } from '@app/shared/video/syndication.model' | 11 | import { Syndication } from '@app/shared/video/syndication.model' |
12 | import { Notifier, ServerService } from '@app/core' | 12 | import { Notifier, ServerService } from '@app/core' |
13 | import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' | 13 | import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' |
14 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
15 | import { isLastMonth, isLastWeek, isToday, isYesterday } from '@shared/core-utils/miscs/date' | ||
16 | |||
17 | enum GroupDate { | ||
18 | UNKNOWN = 0, | ||
19 | TODAY = 1, | ||
20 | YESTERDAY = 2, | ||
21 | LAST_WEEK = 3, | ||
22 | LAST_MONTH = 4, | ||
23 | OLDER = 5 | ||
24 | } | ||
14 | 25 | ||
15 | export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableForReuseHook { | 26 | export 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.html b/client/src/app/shared/video/modals/video-download.component.html index dd01c1388..935d01330 100644 --- a/client/src/app/shared/video/modals/video-download.component.html +++ b/client/src/app/shared/video/modals/video-download.component.html | |||
@@ -31,11 +31,6 @@ | |||
31 | <input type="radio" name="download" id="download-torrent" [(ngModel)]="downloadType" value="torrent"> | 31 | <input type="radio" name="download" id="download-torrent" [(ngModel)]="downloadType" value="torrent"> |
32 | <label i18n for="download-torrent">Torrent (.torrent file)</label> | 32 | <label i18n for="download-torrent">Torrent (.torrent file)</label> |
33 | </div> | 33 | </div> |
34 | |||
35 | <div class="peertube-radio-container"> | ||
36 | <input type="radio" name="download" id="download-magnet" [(ngModel)]="downloadType" value="magnet"> | ||
37 | <label i18n for="download-magnet">Torrent (magnet link)</label> | ||
38 | </div> | ||
39 | </div> | 34 | </div> |
40 | </div> | 35 | </div> |
41 | 36 | ||
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..16f3621b4 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 @@ | |||
1 | import { Component, ElementRef, ViewChild } from '@angular/core' | 1 | import { Component, ElementRef, ViewChild } from '@angular/core' |
2 | import { VideoDetails } from '../../../shared/video/video-details.model' | 2 | import { VideoDetails } from '../../../shared/video/video-details.model' |
3 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | 3 | import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap' |
4 | import { I18n } from '@ngx-translate/i18n-polyfill' | 4 | import { I18n } from '@ngx-translate/i18n-polyfill' |
5 | import { Notifier } from '@app/core' | 5 | import { Notifier } from '@app/core' |
6 | 6 | ||
@@ -12,10 +12,11 @@ import { Notifier } from '@app/core' | |||
12 | export class VideoDownloadComponent { | 12 | export class VideoDownloadComponent { |
13 | @ViewChild('modal') modal: ElementRef | 13 | @ViewChild('modal') modal: ElementRef |
14 | 14 | ||
15 | downloadType: 'direct' | 'torrent' | 'magnet' = 'torrent' | 15 | downloadType: 'direct' | 'torrent' = 'torrent' |
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 () { |
@@ -57,9 +57,6 @@ export class VideoDownloadComponent { | |||
57 | 57 | ||
58 | case 'torrent': | 58 | case 'torrent': |
59 | return file.torrentDownloadUrl | 59 | return file.torrentDownloadUrl |
60 | |||
61 | case 'magnet': | ||
62 | return file.magnetUri | ||
63 | } | 60 | } |
64 | } | 61 | } |
65 | 62 | ||
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 @@ | |||
1 | import { UserRight, VideoConstant, VideoDetails as VideoDetailsServerModel, VideoFile, VideoState } from '../../../../../shared' | 1 | import { VideoConstant, VideoDetails as VideoDetailsServerModel, VideoFile, VideoState } from '../../../../../shared' |
2 | import { AuthUser } from '../../core' | ||
3 | import { Video } from '../../shared/video/video.model' | 2 | import { Video } from '../../shared/video/video.model' |
4 | import { Account } from '@app/shared/account/account.model' | 3 | import { Account } from '@app/shared/account/account.model' |
5 | import { VideoChannel } from '@app/shared/video-channel/video-channel.model' | 4 | import { 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' | |||
20 | import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive' | 20 | import { PeerTubeTemplateDirective } from '@app/shared/angular/peertube-template.directive' |
21 | import { VideoSortField } from '@app/shared/video/sort-field.type' | 21 | import { VideoSortField } from '@app/shared/video/sort-field.type' |
22 | import { ComponentPagination } from '@app/shared/rest/component-pagination.model' | 22 | import { ComponentPagination } from '@app/shared/rest/component-pagination.model' |
23 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
23 | 24 | ||
24 | export type SelectionType = { [ id: number ]: boolean } | 25 | export 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 @@ | |||
1 | export * from './signup-routing.module' | ||
2 | export * from './signup.component' | ||
3 | export * 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.scss b/client/src/app/signup/signup.component.scss deleted file mode 100644 index 90e1e8e74..000000000 --- a/client/src/app/signup/signup.component.scss +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | my-instance-features-table { | ||
5 | display: block; | ||
6 | |||
7 | margin-bottom: 40px; | ||
8 | } | ||
9 | |||
10 | form { | ||
11 | margin: 0 60px 40px 0; | ||
12 | } | ||
13 | |||
14 | .form-group-terms { | ||
15 | margin: 30px 0; | ||
16 | } | ||
17 | |||
18 | .input-group { | ||
19 | @include peertube-input-group(400px); | ||
20 | } | ||
21 | |||
22 | .input-group-append { | ||
23 | height: 30px; | ||
24 | } | ||
25 | |||
26 | input:not([type=submit]) { | ||
27 | @include peertube-input-text(400px); | ||
28 | display: block; | ||
29 | |||
30 | &#username { | ||
31 | width: auto; | ||
32 | flex-grow: 1; | ||
33 | } | ||
34 | } | ||
35 | |||
36 | input[type=submit] { | ||
37 | @include peertube-button; | ||
38 | @include orange-button; | ||
39 | } | ||
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 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { AuthService, Notifier, RedirectService, ServerService } from '@app/core' | ||
3 | import { UserCreate } from '../../../../shared' | ||
4 | import { FormReactive, UserService, UserValidatorsService } from '../shared' | ||
5 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
6 | import { 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 | }) | ||
13 | export 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 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | |||
3 | import { SignupRoutingModule } from './signup-routing.module' | ||
4 | import { SignupComponent } from './signup.component' | ||
5 | import { 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 | }) | ||
24 | export 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 | |||
13 | import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model' | 13 | import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model' |
14 | import { removeElementFromArray } from '@app/shared/misc/utils' | 14 | import { removeElementFromArray } from '@app/shared/misc/utils' |
15 | import { VideoConstant, VideoPrivacy } from '../../../../../../shared' | 15 | import { VideoConstant, VideoPrivacy } from '../../../../../../shared' |
16 | import { 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..e47624dd6 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,8 +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 | |||
105 | this.hydrateFormFromVideo() | 103 | this.hydrateFormFromVideo() |
106 | }, | 104 | }, |
107 | 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-import-url.component.ts b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts index 2dffdbf0e..a5578bebd 100644 --- a/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts +++ b/client/src/app/videos/+video-edit/video-add-components/video-import-url.component.ts | |||
@@ -91,8 +91,6 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom | |||
91 | previewUrl: null | 91 | previewUrl: null |
92 | })) | 92 | })) |
93 | 93 | ||
94 | this.explainedVideoPrivacies = this.videoService.explainedPrivacyLabels(this.videoPrivacies) | ||
95 | |||
96 | this.hydrateFormFromVideo() | 94 | this.hydrateFormFromVideo() |
97 | }, | 95 | }, |
98 | 96 | ||
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- | |||
14 | export abstract class VideoSend extends FormReactive implements OnInit { | 14 | export 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..81c66ff20 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' | |||
3 | import { ActivatedRoute, Router } from '@angular/router' | 3 | import { ActivatedRoute, Router } from '@angular/router' |
4 | import { LoadingBarService } from '@ngx-loading-bar/core' | 4 | import { LoadingBarService } from '@ngx-loading-bar/core' |
5 | import { Notifier } from '@app/core' | 5 | import { Notifier } from '@app/core' |
6 | import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos' | ||
7 | import { ServerService } from '../../core' | 6 | import { ServerService } from '../../core' |
8 | import { FormReactive } from '../../shared' | 7 | import { FormReactive } from '../../shared' |
9 | import { VideoEdit } from '../../shared/video/video-edit.model' | 8 | import { VideoEdit } from '../../shared/video/video-edit.model' |
@@ -13,6 +12,7 @@ import { FormValidatorService } from '@app/shared/forms/form-validators/form-val | |||
13 | import { VideoCaptionService } from '@app/shared/video-caption' | 12 | import { VideoCaptionService } from '@app/shared/video-caption' |
14 | import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model' | 13 | import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model' |
15 | import { VideoDetails } from '@app/shared/video/video-details.model' | 14 | import { VideoDetails } from '@app/shared/video/video-details.model' |
15 | import { VideoPrivacy } from '@shared/models' | ||
16 | 16 | ||
17 | @Component({ | 17 | @Component({ |
18 | selector: 'my-videos-update', | 18 | selector: 'my-videos-update', |
@@ -23,8 +23,6 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { | |||
23 | video: VideoEdit | 23 | video: VideoEdit |
24 | 24 | ||
25 | isUpdatingVideo = false | 25 | isUpdatingVideo = false |
26 | videoPrivacies: VideoConstant<VideoPrivacy>[] = [] | ||
27 | explainedVideoPrivacies: VideoConstant<VideoPrivacy>[] = [] | ||
28 | userVideoChannels: { id: number, label: string, support: string }[] = [] | 26 | userVideoChannels: { id: number, label: string, support: string }[] = [] |
29 | schedulePublicationPossible = false | 27 | schedulePublicationPossible = false |
30 | videoCaptions: VideoCaptionEdit[] = [] | 28 | videoCaptions: VideoCaptionEdit[] = [] |
@@ -49,9 +47,6 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { | |||
49 | ngOnInit () { | 47 | ngOnInit () { |
50 | this.buildForm({}) | 48 | this.buildForm({}) |
51 | 49 | ||
52 | this.serverService.videoPrivaciesLoaded | ||
53 | .subscribe(() => this.videoPrivacies = this.serverService.getVideoPrivacies()) | ||
54 | |||
55 | this.route.data | 50 | this.route.data |
56 | .pipe(map(data => data.videoData)) | 51 | .pipe(map(data => data.videoData)) |
57 | .subscribe(({ video, videoChannels, videoCaptions }) => { | 52 | .subscribe(({ video, videoChannels, videoCaptions }) => { |
@@ -59,14 +54,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { | |||
59 | this.userVideoChannels = videoChannels | 54 | this.userVideoChannels = videoChannels |
60 | this.videoCaptions = videoCaptions | 55 | this.videoCaptions = videoCaptions |
61 | 56 | ||
62 | // We cannot set private a video that was not private | 57 | this.schedulePublicationPossible = this.video.privacy === VideoPrivacy.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 | 58 | ||
71 | const videoFiles = (video as VideoDetails).files | 59 | const videoFiles = (video as VideoDetails).files |
72 | if (videoFiles.length > 1) { // Already transcoded | 60 | if (videoFiles.length > 1) { // Already transcoded |
diff --git a/client/src/app/videos/+video-watch/modal/video-share.component.html b/client/src/app/videos/+video-watch/modal/video-share.component.html index 955b2b80c..82e59d04d 100644 --- a/client/src/app/videos/+video-watch/modal/video-share.component.html +++ b/client/src/app/videos/+video-watch/modal/video-share.component.html | |||
@@ -5,53 +5,167 @@ | |||
5 | </div> | 5 | </div> |
6 | 6 | ||
7 | <div class="modal-body"> | 7 | <div class="modal-body"> |
8 | <ngb-tabset class="root-tabset bootstrap" (tabChange)="onTabChange($event)"> | ||
8 | 9 | ||
9 | <div class="start-at"> | 10 | <ngb-tab i18n-title title="URL" id="url"> |
10 | <my-peertube-checkbox | 11 | <ng-template ngbTabContent> |
11 | inputName="startAt" [(ngModel)]="startAtCheckbox" | 12 | |
12 | i18n-labelText labelText="Start at" | 13 | <div class="tab-content"> |
13 | ></my-peertube-checkbox> | 14 | <div class="input-group"> |
14 | 15 | <input #urlInput (click)="urlInput.select()" type="text" class="form-control readonly" readonly [value]="getVideoUrl()" /> | |
15 | <my-timestamp-input | 16 | <div class="input-group-append"> |
16 | [timestamp]="currentVideoTimestamp" | 17 | <button [ngxClipboard]="urlInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary"> |
17 | [maxTimestamp]="video.duration" | 18 | <span class="glyphicon glyphicon-copy"></span> |
18 | [disabled]="!startAtCheckbox" | 19 | </button> |
19 | [(ngModel)]="currentVideoTimestamp" | 20 | </div> |
20 | > | 21 | </div> |
21 | </my-timestamp-input> | 22 | </div> |
22 | </div> | 23 | |
24 | </ng-template> | ||
25 | </ngb-tab> | ||
26 | |||
27 | <ngb-tab i18n-title title="QR-Code" id="qrcode"> | ||
28 | <ng-template ngbTabContent> | ||
29 | <div class="tab-content"> | ||
30 | <ngx-qrcode qrc-element-type="url" [qrc-value]="getVideoUrl()" qrc-errorCorrectionLevel="Q"></ngx-qrcode> | ||
31 | </div> | ||
32 | </ng-template> | ||
33 | </ngb-tab> | ||
34 | |||
35 | <ngb-tab i18n-title title="Embed" id="embed"> | ||
36 | <ng-template ngbTabContent> | ||
37 | <div class="tab-content"> | ||
38 | <div class="input-group"> | ||
39 | <input #shareInput (click)="shareInput.select()" type="text" class="form-control readonly" readonly [value]="getVideoIframeCode()" /> | ||
40 | <div class="input-group-append"> | ||
41 | <button [ngxClipboard]="shareInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary"> | ||
42 | <span class="glyphicon glyphicon-copy"></span> | ||
43 | </button> | ||
44 | </div> | ||
45 | </div> | ||
46 | |||
47 | <div i18n *ngIf="notSecure()" class="alert alert-warning"> | ||
48 | The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites). | ||
49 | </div> | ||
50 | </div> | ||
51 | </ng-template> | ||
52 | </ngb-tab> | ||
53 | |||
54 | </ngb-tabset> | ||
23 | 55 | ||
24 | <div class="form-group"> | 56 | <div class="filters"> |
25 | <label i18n>URL</label> | 57 | <div> |
26 | <div class="input-group input-group-sm"> | 58 | <div class="form-group start-at"> |
27 | <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getVideoUrl()" /> | 59 | <my-peertube-checkbox |
28 | <div class="input-group-append"> | 60 | inputName="startAt" [(ngModel)]="customizations.startAtCheckbox" |
29 | <button [ngxClipboard]="urlInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary"> | 61 | i18n-labelText labelText="Start at" |
30 | <span class="glyphicon glyphicon-copy"></span> | 62 | ></my-peertube-checkbox> |
31 | </button> | 63 | |
64 | <my-timestamp-input | ||
65 | [timestamp]="customizations.startAt" | ||
66 | [maxTimestamp]="video.duration" | ||
67 | [disabled]="!customizations.startAtCheckbox" | ||
68 | [(ngModel)]="customizations.startAt" | ||
69 | > | ||
70 | </my-timestamp-input> | ||
32 | </div> | 71 | </div> |
33 | </div> | ||
34 | </div> | ||
35 | 72 | ||
36 | <div class="form-group qr-code-group"> | 73 | <div *ngIf="videoCaptions.length !== 0" class="form-group video-caption-block"> |
37 | <label i18n>QR-Code</label> | 74 | <my-peertube-checkbox |
38 | <ngx-qrcode qrc-element-type="url" [qrc-value]="getVideoUrl()" qrc-errorCorrectionLevel="Q"></ngx-qrcode> | 75 | inputName="subtitleCheckbox" [(ngModel)]="customizations.subtitleCheckbox" |
39 | </div> | 76 | i18n-labelText labelText="Auto select subtitle" |
77 | ></my-peertube-checkbox> | ||
40 | 78 | ||
41 | <div class="form-group"> | 79 | <div class="peertube-select-container" [ngClass]="{ disabled: !customizations.subtitleCheckbox }"> |
42 | <label i18n>Embed</label> | 80 | <select [(ngModel)]="customizations.subtitle" [disabled]="!customizations.subtitleCheckbox"> |
43 | <div class="input-group input-group-sm"> | 81 | <option *ngFor="let caption of videoCaptions" [value]="caption.language.id">{{ caption.language.label }}</option> |
44 | <input #shareInput (click)="shareInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getVideoIframeCode()" /> | 82 | </select> |
45 | <div class="input-group-append"> | 83 | </div> |
46 | <button [ngxClipboard]="shareInput" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary"> | ||
47 | <span class="glyphicon glyphicon-copy"></span> | ||
48 | </button> | ||
49 | </div> | 84 | </div> |
50 | </div> | 85 | </div> |
51 | </div> | ||
52 | 86 | ||
53 | <div i18n *ngIf="notSecure()" class="alert alert-warning"> | 87 | <div (click)="isAdvancedCustomizationCollapsed = !isAdvancedCustomizationCollapsed" role="button" class="advanced-filters-button" |
54 | The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites). | 88 | [attr.aria-expanded]="!isAdvancedCustomizationCollapsed" aria-controls="collapseBasic"> |
89 | |||
90 | <ng-container *ngIf="isAdvancedCustomizationCollapsed"> | ||
91 | <span class="glyphicon glyphicon-menu-down"></span> | ||
92 | |||
93 | <ng-container i18n> | ||
94 | More customization | ||
95 | </ng-container> | ||
96 | </ng-container> | ||
97 | |||
98 | <ng-container *ngIf="!isAdvancedCustomizationCollapsed"> | ||
99 | <span class="glyphicon glyphicon-menu-up"></span> | ||
100 | |||
101 | <ng-container i18n> | ||
102 | Less customization | ||
103 | </ng-container> | ||
104 | </ng-container> | ||
105 | </div> | ||
106 | |||
107 | <div class="advanced-filters collapse-transition" [ngbCollapse]="isAdvancedCustomizationCollapsed"> | ||
108 | <div> | ||
109 | <div class="form-group stop-at"> | ||
110 | <my-peertube-checkbox | ||
111 | inputName="stopAt" [(ngModel)]="customizations.stopAtCheckbox" | ||
112 | i18n-labelText labelText="Stop at" | ||
113 | ></my-peertube-checkbox> | ||
114 | |||
115 | <my-timestamp-input | ||
116 | [timestamp]="customizations.stopAt" | ||
117 | [maxTimestamp]="video.duration" | ||
118 | [disabled]="!customizations.stopAtCheckbox" | ||
119 | [(ngModel)]="customizations.stopAt" | ||
120 | > | ||
121 | </my-timestamp-input> | ||
122 | </div> | ||
123 | |||
124 | <div class="form-group"> | ||
125 | <my-peertube-checkbox | ||
126 | inputName="autoplay" [(ngModel)]="customizations.autoplay" | ||
127 | i18n-labelText labelText="Autoplay" | ||
128 | ></my-peertube-checkbox> | ||
129 | </div> | ||
130 | |||
131 | <div class="form-group"> | ||
132 | <my-peertube-checkbox | ||
133 | inputName="muted" [(ngModel)]="customizations.muted" | ||
134 | i18n-labelText labelText="Muted" | ||
135 | ></my-peertube-checkbox> | ||
136 | </div> | ||
137 | |||
138 | <div class="form-group"> | ||
139 | <my-peertube-checkbox | ||
140 | inputName="loop" [(ngModel)]="customizations.loop" | ||
141 | i18n-labelText labelText="Loop" | ||
142 | ></my-peertube-checkbox> | ||
143 | </div> | ||
144 | </div> | ||
145 | |||
146 | <ng-container *ngIf="isInEmbedTab()"> | ||
147 | <div class="form-group"> | ||
148 | <my-peertube-checkbox | ||
149 | inputName="title" [(ngModel)]="customizations.title" | ||
150 | i18n-labelText labelText="Display video title" | ||
151 | ></my-peertube-checkbox> | ||
152 | </div> | ||
153 | |||
154 | <div class="form-group"> | ||
155 | <my-peertube-checkbox | ||
156 | inputName="warningTitle" [(ngModel)]="customizations.warningTitle" | ||
157 | i18n-labelText labelText="Display privacy warning" | ||
158 | ></my-peertube-checkbox> | ||
159 | </div> | ||
160 | |||
161 | <div class="form-group"> | ||
162 | <my-peertube-checkbox | ||
163 | inputName="controls" [(ngModel)]="customizations.controls" | ||
164 | i18n-labelText labelText="Display player controls" | ||
165 | ></my-peertube-checkbox> | ||
166 | </div> | ||
167 | </ng-container> | ||
168 | </div> | ||
55 | </div> | 169 | </div> |
56 | </div> | 170 | </div> |
57 | 171 | ||
diff --git a/client/src/app/videos/+video-watch/modal/video-share.component.scss b/client/src/app/videos/+video-watch/modal/video-share.component.scss index 472a45920..c48abf9e0 100644 --- a/client/src/app/videos/+video-watch/modal/video-share.component.scss +++ b/client/src/app/videos/+video-watch/modal/video-share.component.scss | |||
@@ -1,5 +1,9 @@ | |||
1 | @import '~bootstrap/scss/functions'; | 1 | @import '_mixins'; |
2 | @import '~bootstrap/scss/variables'; | 2 | @import '_variables'; |
3 | |||
4 | .peertube-select-container { | ||
5 | @include peertube-select-container(200px); | ||
6 | } | ||
3 | 7 | ||
4 | .action-button-cancel { | 8 | .action-button-cancel { |
5 | margin-right: 0 !important; | 9 | margin-right: 0 !important; |
@@ -9,13 +13,65 @@ | |||
9 | text-align: center; | 13 | text-align: center; |
10 | } | 14 | } |
11 | 15 | ||
12 | .start-at { | 16 | .tab-content { |
17 | margin-top: 30px; | ||
13 | display: flex; | 18 | display: flex; |
14 | justify-content: center; | 19 | justify-content: center; |
15 | margin-top: 10px; | ||
16 | align-items: center; | 20 | align-items: center; |
21 | flex-direction: column; | ||
22 | } | ||
23 | |||
24 | .alert { | ||
25 | margin-top: 20px; | ||
26 | } | ||
27 | |||
28 | input.readonly { | ||
29 | font-size: 15px; | ||
30 | } | ||
31 | |||
32 | .filters { | ||
33 | margin-top: 30px; | ||
34 | padding-top: 30px; | ||
35 | border-top: 1px solid $separator-border-color; | ||
36 | |||
37 | .advanced-filters-button { | ||
38 | display: flex; | ||
39 | justify-content: center; | ||
40 | align-items: center; | ||
41 | margin-top: 30px; | ||
42 | font-size: 16px; | ||
43 | font-weight: $font-semibold; | ||
44 | cursor: pointer; | ||
45 | |||
46 | .glyphicon { | ||
47 | margin-right: 5px; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | .form-group { | ||
52 | margin-bottom: 0; | ||
53 | height: 34px; | ||
54 | display: flex; | ||
55 | align-items: center; | ||
56 | } | ||
57 | |||
58 | .video-caption-block { | ||
59 | display: flex; | ||
60 | align-items: center; | ||
61 | |||
62 | .peertube-select-container { | ||
63 | margin-left: 10px; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | .start-at, | ||
68 | .stop-at { | ||
69 | width: 300px; | ||
70 | display: flex; | ||
71 | align-items: center; | ||
17 | 72 | ||
18 | my-timestamp-input { | 73 | my-timestamp-input { |
19 | margin-left: 10px; | 74 | margin-left: 10px; |
75 | } | ||
20 | } | 76 | } |
21 | } | 77 | } |
diff --git a/client/src/app/videos/+video-watch/modal/video-share.component.ts b/client/src/app/videos/+video-watch/modal/video-share.component.ts index 6565d7f88..eaaf6b902 100644 --- a/client/src/app/videos/+video-watch/modal/video-share.component.ts +++ b/client/src/app/videos/+video-watch/modal/video-share.component.ts | |||
@@ -3,8 +3,26 @@ import { Notifier } from '@app/core' | |||
3 | import { VideoDetails } from '../../../shared/video/video-details.model' | 3 | import { VideoDetails } from '../../../shared/video/video-details.model' |
4 | import { buildVideoEmbed, buildVideoLink } from '../../../../assets/player/utils' | 4 | import { buildVideoEmbed, buildVideoLink } from '../../../../assets/player/utils' |
5 | import { I18n } from '@ngx-translate/i18n-polyfill' | 5 | import { I18n } from '@ngx-translate/i18n-polyfill' |
6 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | 6 | import { NgbModal, NgbTabChangeEvent } from '@ng-bootstrap/ng-bootstrap' |
7 | import { durationToString } from '@app/shared/misc/utils' | 7 | import { VideoCaption } from '@shared/models' |
8 | |||
9 | type Customizations = { | ||
10 | startAtCheckbox: boolean | ||
11 | startAt: number | ||
12 | |||
13 | stopAtCheckbox: boolean | ||
14 | stopAt: number | ||
15 | |||
16 | subtitleCheckbox: boolean | ||
17 | subtitle: string | ||
18 | |||
19 | loop: boolean | ||
20 | autoplay: boolean | ||
21 | muted: boolean | ||
22 | title: boolean | ||
23 | warningTitle: boolean | ||
24 | controls: boolean | ||
25 | } | ||
8 | 26 | ||
9 | @Component({ | 27 | @Component({ |
10 | selector: 'my-video-share', | 28 | selector: 'my-video-share', |
@@ -15,9 +33,13 @@ export class VideoShareComponent { | |||
15 | @ViewChild('modal') modal: ElementRef | 33 | @ViewChild('modal') modal: ElementRef |
16 | 34 | ||
17 | @Input() video: VideoDetails = null | 35 | @Input() video: VideoDetails = null |
36 | @Input() videoCaptions: VideoCaption[] = [] | ||
18 | 37 | ||
19 | currentVideoTimestamp: number | 38 | activeId: 'url' | 'qrcode' | 'embed' |
20 | startAtCheckbox = false | 39 | customizations: Customizations |
40 | isAdvancedCustomizationCollapsed = true | ||
41 | |||
42 | private currentVideoTimestamp: number | ||
21 | 43 | ||
22 | constructor ( | 44 | constructor ( |
23 | private modalService: NgbModal, | 45 | private modalService: NgbModal, |
@@ -26,19 +48,47 @@ export class VideoShareComponent { | |||
26 | ) { } | 48 | ) { } |
27 | 49 | ||
28 | show (currentVideoTimestamp?: number) { | 50 | show (currentVideoTimestamp?: number) { |
29 | this.currentVideoTimestamp = currentVideoTimestamp ? Math.floor(currentVideoTimestamp) : 0 | 51 | this.currentVideoTimestamp = currentVideoTimestamp |
52 | |||
53 | let subtitle: string | ||
54 | if (this.videoCaptions.length !== 0) { | ||
55 | subtitle = this.videoCaptions[0].language.id | ||
56 | } | ||
57 | |||
58 | this.customizations = { | ||
59 | startAtCheckbox: false, | ||
60 | startAt: currentVideoTimestamp ? Math.floor(currentVideoTimestamp) : 0, | ||
61 | |||
62 | stopAtCheckbox: false, | ||
63 | stopAt: this.video.duration, | ||
64 | |||
65 | subtitleCheckbox: false, | ||
66 | subtitle, | ||
67 | |||
68 | loop: false, | ||
69 | autoplay: false, | ||
70 | muted: false, | ||
71 | |||
72 | // Embed options | ||
73 | title: true, | ||
74 | warningTitle: true, | ||
75 | controls: true | ||
76 | } | ||
30 | 77 | ||
31 | this.modalService.open(this.modal) | 78 | this.modalService.open(this.modal) |
32 | } | 79 | } |
33 | 80 | ||
34 | getVideoIframeCode () { | 81 | getVideoIframeCode () { |
35 | const embedUrl = buildVideoLink(this.getVideoTimestampIfEnabled(), this.video.embedUrl) | 82 | const options = this.getOptions(this.video.embedUrl) |
36 | 83 | ||
84 | const embedUrl = buildVideoLink(options) | ||
37 | return buildVideoEmbed(embedUrl) | 85 | return buildVideoEmbed(embedUrl) |
38 | } | 86 | } |
39 | 87 | ||
40 | getVideoUrl () { | 88 | getVideoUrl () { |
41 | return buildVideoLink(this.getVideoTimestampIfEnabled()) | 89 | const options = this.getOptions() |
90 | |||
91 | return buildVideoLink(options) | ||
42 | } | 92 | } |
43 | 93 | ||
44 | notSecure () { | 94 | notSecure () { |
@@ -49,9 +99,30 @@ export class VideoShareComponent { | |||
49 | this.notifier.success(this.i18n('Copied')) | 99 | this.notifier.success(this.i18n('Copied')) |
50 | } | 100 | } |
51 | 101 | ||
52 | private getVideoTimestampIfEnabled () { | 102 | onTabChange (event: NgbTabChangeEvent) { |
53 | if (this.startAtCheckbox === true) return this.currentVideoTimestamp | 103 | this.activeId = event.nextId as any |
104 | } | ||
105 | |||
106 | isInEmbedTab () { | ||
107 | return this.activeId === 'embed' | ||
108 | } | ||
109 | |||
110 | private getOptions (baseUrl?: string) { | ||
111 | return { | ||
112 | baseUrl, | ||
113 | |||
114 | startTime: this.customizations.startAtCheckbox ? this.customizations.startAt : undefined, | ||
115 | stopTime: this.customizations.stopAtCheckbox ? this.customizations.stopAt : undefined, | ||
116 | |||
117 | subtitle: this.customizations.subtitleCheckbox ? this.customizations.subtitle : undefined, | ||
118 | |||
119 | loop: this.customizations.loop, | ||
120 | autoplay: this.customizations.autoplay, | ||
121 | muted: this.customizations.muted, | ||
54 | 122 | ||
55 | return undefined | 123 | title: this.customizations.title, |
124 | warningTitle: this.customizations.warningTitle, | ||
125 | controls: this.customizations.controls | ||
126 | } | ||
56 | } | 127 | } |
57 | } | 128 | } |
diff --git a/client/src/app/videos/+video-watch/video-watch.component.html b/client/src/app/videos/+video-watch/video-watch.component.html index 2e39b9c6b..6a02f630a 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html | |||
@@ -219,5 +219,5 @@ | |||
219 | 219 | ||
220 | <ng-template [ngIf]="video !== null"> | 220 | <ng-template [ngIf]="video !== null"> |
221 | <my-video-support #videoSupportModal [video]="video"></my-video-support> | 221 | <my-video-support #videoSupportModal [video]="video"></my-video-support> |
222 | <my-video-share #videoShareModal [video]="video"></my-video-share> | 222 | <my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions"></my-video-share> |
223 | </ng-template> | 223 | </ng-template> |
diff --git a/client/src/app/videos/+video-watch/video-watch.component.scss b/client/src/app/videos/+video-watch/video-watch.component.scss index bada9bae8..35ea0fffd 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.scss +++ b/client/src/app/videos/+video-watch/video-watch.component.scss | |||
@@ -347,6 +347,7 @@ $player-factor: 1.7; // 16/9 | |||
347 | /deep/ .other-videos { | 347 | /deep/ .other-videos { |
348 | padding-left: 15px; | 348 | padding-left: 15px; |
349 | flex-basis: $other-videos-width; | 349 | flex-basis: $other-videos-width; |
350 | min-width: $other-videos-width; | ||
350 | 351 | ||
351 | .title-page { | 352 | .title-page { |
352 | margin-top: 0 !important; | 353 | margin-top: 0 !important; |
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..3f1a98f89 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' | |||
6 | import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' | 6 | import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' |
7 | import { MetaService } from '@ngx-meta/core' | 7 | import { MetaService } from '@ngx-meta/core' |
8 | import { Notifier, ServerService } from '@app/core' | 8 | import { Notifier, ServerService } from '@app/core' |
9 | import { forkJoin, Subscription } from 'rxjs' | 9 | import { forkJoin, Observable, Subscription } from 'rxjs' |
10 | import { Hotkey, HotkeysService } from 'angular2-hotkeys' | 10 | import { Hotkey, HotkeysService } from 'angular2-hotkeys' |
11 | import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared' | 11 | import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared' |
12 | import { AuthService, ConfirmService } from '../../core' | 12 | import { AuthService, ConfirmService } from '../../core' |
@@ -20,6 +20,7 @@ import { environment } from '../../../environments/environment' | |||
20 | import { VideoCaptionService } from '@app/shared/video-caption' | 20 | import { VideoCaptionService } from '@app/shared/video-caption' |
21 | import { MarkdownService } from '@app/shared/renderer' | 21 | import { MarkdownService } from '@app/shared/renderer' |
22 | import { | 22 | import { |
23 | CustomizationOptions, | ||
23 | P2PMediaLoaderOptions, | 24 | P2PMediaLoaderOptions, |
24 | PeertubePlayerManager, | 25 | PeertubePlayerManager, |
25 | PeertubePlayerManagerOptions, | 26 | PeertubePlayerManagerOptions, |
@@ -28,8 +29,9 @@ import { | |||
28 | import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' | 29 | import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' |
29 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' | 30 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' |
30 | import { Video } from '@app/shared/video/video.model' | 31 | import { Video } from '@app/shared/video/video.model' |
31 | import { isWebRTCDisabled } from '../../../assets/player/utils' | 32 | import { isWebRTCDisabled, timeToInt } from '../../../assets/player/utils' |
32 | import { VideoWatchPlaylistComponent } from '@app/videos/+video-watch/video-watch-playlist.component' | 33 | import { VideoWatchPlaylistComponent } from '@app/videos/+video-watch/video-watch-playlist.component' |
34 | import { getStoredTheater } from '../../../assets/player/peertube-player-local-storage' | ||
33 | 35 | ||
34 | @Component({ | 36 | @Component({ |
35 | selector: 'my-video-watch', | 37 | selector: 'my-video-watch', |
@@ -48,9 +50,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
48 | playerElement: HTMLVideoElement | 50 | playerElement: HTMLVideoElement |
49 | theaterEnabled = false | 51 | theaterEnabled = false |
50 | userRating: UserVideoRateType = null | 52 | userRating: UserVideoRateType = null |
51 | video: VideoDetails = null | ||
52 | descriptionLoading = false | 53 | descriptionLoading = false |
53 | 54 | ||
55 | video: VideoDetails = null | ||
56 | videoCaptions: VideoCaption[] = [] | ||
57 | |||
54 | playlist: VideoPlaylist = null | 58 | playlist: VideoPlaylist = null |
55 | 59 | ||
56 | completeDescriptionShown = false | 60 | completeDescriptionShown = false |
@@ -120,6 +124,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
120 | }) | 124 | }) |
121 | 125 | ||
122 | this.initHotkeys() | 126 | this.initHotkeys() |
127 | |||
128 | this.theaterEnabled = getStoredTheater() | ||
123 | } | 129 | } |
124 | 130 | ||
125 | ngOnDestroy () { | 131 | ngOnDestroy () { |
@@ -135,22 +141,18 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
135 | 141 | ||
136 | setLike () { | 142 | setLike () { |
137 | if (this.isUserLoggedIn() === false) return | 143 | if (this.isUserLoggedIn() === false) return |
138 | if (this.userRating === 'like') { | 144 | |
139 | // Already liked this video | 145 | // Already liked this video |
140 | this.setRating('none') | 146 | if (this.userRating === 'like') this.setRating('none') |
141 | } else { | 147 | else this.setRating('like') |
142 | this.setRating('like') | ||
143 | } | ||
144 | } | 148 | } |
145 | 149 | ||
146 | setDislike () { | 150 | setDislike () { |
147 | if (this.isUserLoggedIn() === false) return | 151 | if (this.isUserLoggedIn() === false) return |
148 | if (this.userRating === 'dislike') { | 152 | |
149 | // Already disliked this video | 153 | // Already disliked this video |
150 | this.setRating('none') | 154 | if (this.userRating === 'dislike') this.setRating('none') |
151 | } else { | 155 | else this.setRating('dislike') |
152 | this.setRating('dislike') | ||
153 | } | ||
154 | } | 156 | } |
155 | 157 | ||
156 | showMoreDescription () { | 158 | showMoreDescription () { |
@@ -249,12 +251,20 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
249 | ) | 251 | ) |
250 | .subscribe(([ video, captionsResult ]) => { | 252 | .subscribe(([ video, captionsResult ]) => { |
251 | const queryParams = this.route.snapshot.queryParams | 253 | 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 | 254 | ||
257 | this.onVideoFetched(video, captionsResult.data, { startTime, stopTime, subtitle, playerMode }) | 255 | const urlOptions = { |
256 | startTime: queryParams.start, | ||
257 | stopTime: queryParams.stop, | ||
258 | |||
259 | muted: queryParams.muted, | ||
260 | loop: queryParams.loop, | ||
261 | subtitle: queryParams.subtitle, | ||
262 | |||
263 | playerMode: queryParams.mode, | ||
264 | peertubeLink: false | ||
265 | } | ||
266 | |||
267 | this.onVideoFetched(video, captionsResult.data, urlOptions) | ||
258 | .catch(err => this.handleError(err)) | 268 | .catch(err => this.handleError(err)) |
259 | }) | 269 | }) |
260 | } | 270 | } |
@@ -279,6 +289,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
279 | private updateVideoDescription (description: string) { | 289 | private updateVideoDescription (description: string) { |
280 | this.video.description = description | 290 | this.video.description = description |
281 | this.setVideoDescriptionHTML() | 291 | this.setVideoDescriptionHTML() |
292 | .catch(err => console.error(err)) | ||
282 | } | 293 | } |
283 | 294 | ||
284 | private async setVideoDescriptionHTML () { | 295 | private async setVideoDescriptionHTML () { |
@@ -327,9 +338,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
327 | private async onVideoFetched ( | 338 | private async onVideoFetched ( |
328 | video: VideoDetails, | 339 | video: VideoDetails, |
329 | videoCaptions: VideoCaption[], | 340 | videoCaptions: VideoCaption[], |
330 | urlOptions: { startTime?: number, stopTime?: number, subtitle?: string, playerMode?: string } | 341 | urlOptions: CustomizationOptions & { playerMode: PlayerMode } |
331 | ) { | 342 | ) { |
332 | this.video = video | 343 | this.video = video |
344 | this.videoCaptions = videoCaptions | ||
333 | 345 | ||
334 | // Re init attributes | 346 | // Re init attributes |
335 | this.descriptionLoading = false | 347 | this.descriptionLoading = false |
@@ -339,7 +351,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
339 | 351 | ||
340 | this.videoWatchPlaylist.updatePlaylistIndex(video) | 352 | this.videoWatchPlaylist.updatePlaylistIndex(video) |
341 | 353 | ||
342 | let startTime = urlOptions.startTime || (this.video.userHistory ? this.video.userHistory.currentTime : 0) | 354 | let startTime = timeToInt(urlOptions.startTime) || (this.video.userHistory ? this.video.userHistory.currentTime : 0) |
343 | // If we are at the end of the video, reset the timer | 355 | // If we are at the end of the video, reset the timer |
344 | if (this.video.duration - startTime <= 1) startTime = 0 | 356 | if (this.video.duration - startTime <= 1) startTime = 0 |
345 | 357 | ||
@@ -378,20 +390,26 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
378 | enableHotkeys: true, | 390 | enableHotkeys: true, |
379 | inactivityTimeout: 2500, | 391 | inactivityTimeout: 2500, |
380 | poster: this.video.previewUrl, | 392 | poster: this.video.previewUrl, |
393 | |||
381 | startTime, | 394 | startTime, |
382 | stopTime: urlOptions.stopTime, | 395 | stopTime: urlOptions.stopTime, |
396 | controls: urlOptions.controls, | ||
397 | muted: urlOptions.muted, | ||
398 | loop: urlOptions.loop, | ||
399 | subtitle: urlOptions.subtitle, | ||
400 | |||
401 | peertubeLink: urlOptions.peertubeLink, | ||
383 | 402 | ||
384 | theaterMode: true, | 403 | theaterMode: true, |
385 | captions: videoCaptions.length !== 0, | 404 | captions: videoCaptions.length !== 0, |
386 | peertubeLink: false, | ||
387 | 405 | ||
388 | videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE ? this.videoService.getVideoViewUrl(this.video.uuid) : null, | 406 | videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE |
407 | ? this.videoService.getVideoViewUrl(this.video.uuid) | ||
408 | : null, | ||
389 | embedUrl: this.video.embedUrl, | 409 | embedUrl: this.video.embedUrl, |
390 | 410 | ||
391 | language: this.localeId, | 411 | language: this.localeId, |
392 | 412 | ||
393 | subtitle: urlOptions.subtitle, | ||
394 | |||
395 | userWatching: this.user && this.user.videosHistoryEnabled === true ? { | 413 | userWatching: this.user && this.user.videosHistoryEnabled === true ? { |
396 | url: this.videoService.getUserWatchingVideoUrl(this.video.uuid), | 414 | url: this.videoService.getUserWatchingVideoUrl(this.video.uuid), |
397 | authorizationHeader: this.authService.getRequestHeaderValue() | 415 | authorizationHeader: this.authService.getRequestHeaderValue() |
@@ -433,7 +451,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
433 | 451 | ||
434 | this.zone.runOutsideAngular(async () => { | 452 | this.zone.runOutsideAngular(async () => { |
435 | this.player = await PeertubePlayerManager.initialize(mode, options) | 453 | this.player = await PeertubePlayerManager.initialize(mode, options) |
436 | this.theaterEnabled = this.player.theaterEnabled | ||
437 | 454 | ||
438 | this.player.on('customError', ({ err }: { err: any }) => this.handleError(err)) | 455 | this.player.on('customError', ({ err }: { err: any }) => this.handleError(err)) |
439 | 456 | ||
@@ -466,20 +483,13 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
466 | } | 483 | } |
467 | 484 | ||
468 | private setRating (nextRating: UserVideoRateType) { | 485 | private setRating (nextRating: UserVideoRateType) { |
469 | let method | 486 | const ratingMethods: { [id in UserVideoRateType]: (id: number) => Observable<any> } = { |
470 | switch (nextRating) { | 487 | like: this.videoService.setVideoLike, |
471 | case 'like': | 488 | dislike: this.videoService.setVideoDislike, |
472 | method = this.videoService.setVideoLike | 489 | 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 | } | 490 | } |
481 | 491 | ||
482 | method.call(this.videoService, this.video.id) | 492 | ratingMethods[nextRating].call(this.videoService, this.video.id) |
483 | .subscribe( | 493 | .subscribe( |
484 | () => { | 494 | () => { |
485 | // Update the video like attribute | 495 | // Update the video like attribute |
@@ -545,25 +555,29 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
545 | private flushPlayer () { | 555 | private flushPlayer () { |
546 | // Remove player if it exists | 556 | // Remove player if it exists |
547 | if (this.player) { | 557 | if (this.player) { |
548 | this.player.dispose() | 558 | try { |
549 | this.player = undefined | 559 | this.player.dispose() |
560 | this.player = undefined | ||
561 | } catch (err) { | ||
562 | console.error('Cannot dispose player.', err) | ||
563 | } | ||
550 | } | 564 | } |
551 | } | 565 | } |
552 | 566 | ||
553 | private initHotkeys () { | 567 | private initHotkeys () { |
554 | this.hotkeys = [ | 568 | this.hotkeys = [ |
555 | new Hotkey('shift+l', (event: KeyboardEvent): boolean => { | 569 | new Hotkey('shift+l', () => { |
556 | this.setLike() | 570 | this.setLike() |
557 | return false | 571 | return false |
558 | }, undefined, this.i18n('Like the video')), | 572 | }, undefined, this.i18n('Like the video')), |
559 | new Hotkey('shift+d', (event: KeyboardEvent): boolean => { | 573 | |
574 | new Hotkey('shift+d', () => { | ||
560 | this.setDislike() | 575 | this.setDislike() |
561 | return false | 576 | return false |
562 | }, undefined, this.i18n('Dislike the video')), | 577 | }, undefined, this.i18n('Dislike the video')), |
563 | new Hotkey('shift+s', (event: KeyboardEvent): boolean => { | 578 | |
564 | this.subscribeButton.subscribed ? | 579 | new Hotkey('shift+s', () => { |
565 | this.subscribeButton.unsubscribe() : | 580 | this.subscribeButton.subscribed ? this.subscribeButton.unsubscribe() : this.subscribeButton.subscribe() |
566 | this.subscribeButton.subscribe() | ||
567 | return false | 581 | return false |
568 | }, undefined, this.i18n('Subscribe to the account')) | 582 | }, undefined, this.i18n('Subscribe to the account')) |
569 | ] | 583 | ] |
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' | |||
17 | export class VideoRecentlyAddedComponent extends AbstractVideoList implements OnInit, OnDestroy { | 17 | export 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-local-storage.ts b/client/src/assets/player/peertube-player-local-storage.ts index 059fca308..f6c5c5419 100644 --- a/client/src/assets/player/peertube-player-local-storage.ts +++ b/client/src/assets/player/peertube-player-local-storage.ts | |||
@@ -29,7 +29,7 @@ function getStoredTheater () { | |||
29 | const value = getLocalStorage('theater-enabled') | 29 | const value = getLocalStorage('theater-enabled') |
30 | if (value !== null && value !== undefined) return value === 'true' | 30 | if (value !== null && value !== undefined) return value === 'true' |
31 | 31 | ||
32 | return undefined | 32 | return false |
33 | } | 33 | } |
34 | 34 | ||
35 | function saveVolumeInStore (value: number) { | 35 | function saveVolumeInStore (value: number) { |
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 6cdd54372..083c621d2 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts | |||
@@ -39,7 +39,19 @@ export type P2PMediaLoaderOptions = { | |||
39 | videoFiles: VideoFile[] | 39 | videoFiles: VideoFile[] |
40 | } | 40 | } |
41 | 41 | ||
42 | export type CommonOptions = { | 42 | export interface CustomizationOptions { |
43 | startTime: number | string | ||
44 | stopTime: number | string | ||
45 | |||
46 | controls?: boolean | ||
47 | muted?: boolean | ||
48 | loop?: boolean | ||
49 | subtitle?: string | ||
50 | |||
51 | peertubeLink: boolean | ||
52 | } | ||
53 | |||
54 | export interface CommonOptions extends CustomizationOptions { | ||
43 | playerElement: HTMLVideoElement | 55 | playerElement: HTMLVideoElement |
44 | onPlayerElementChange: (element: HTMLVideoElement) => void | 56 | onPlayerElementChange: (element: HTMLVideoElement) => void |
45 | 57 | ||
@@ -48,21 +60,14 @@ export type CommonOptions = { | |||
48 | enableHotkeys: boolean | 60 | enableHotkeys: boolean |
49 | inactivityTimeout: number | 61 | inactivityTimeout: number |
50 | poster: string | 62 | poster: string |
51 | startTime: number | string | ||
52 | stopTime: number | string | ||
53 | 63 | ||
54 | theaterMode: boolean | 64 | theaterMode: boolean |
55 | captions: boolean | 65 | captions: boolean |
56 | peertubeLink: boolean | ||
57 | 66 | ||
58 | videoViewUrl: string | 67 | videoViewUrl: string |
59 | embedUrl: string | 68 | embedUrl: string |
60 | 69 | ||
61 | language?: string | 70 | language?: string |
62 | controls?: boolean | ||
63 | muted?: boolean | ||
64 | loop?: boolean | ||
65 | subtitle?: string | ||
66 | 71 | ||
67 | videoCaptions: VideoJSCaption[] | 72 | videoCaptions: VideoJSCaption[] |
68 | 73 | ||
@@ -117,8 +122,17 @@ export class PeertubePlayerManager { | |||
117 | videojs(options.common.playerElement, videojsOptions, function (this: any) { | 122 | videojs(options.common.playerElement, videojsOptions, function (this: any) { |
118 | const player = this | 123 | const player = this |
119 | 124 | ||
120 | player.tech_.one('error', () => self.maybeFallbackToWebTorrent(mode, player, options)) | 125 | let alreadyFallback = false |
121 | player.one('error', () => self.maybeFallbackToWebTorrent(mode, player, options)) | 126 | |
127 | player.tech_.one('error', () => { | ||
128 | if (!alreadyFallback) self.maybeFallbackToWebTorrent(mode, player, options) | ||
129 | alreadyFallback = true | ||
130 | }) | ||
131 | |||
132 | player.one('error', () => { | ||
133 | if (!alreadyFallback) self.maybeFallbackToWebTorrent(mode, player, options) | ||
134 | alreadyFallback = true | ||
135 | }) | ||
122 | 136 | ||
123 | self.addContextMenu(mode, player, options.common.embedUrl) | 137 | self.addContextMenu(mode, player, options.common.embedUrl) |
124 | 138 | ||
@@ -432,7 +446,7 @@ export class PeertubePlayerManager { | |||
432 | label: player.localize('Copy the video URL at the current time'), | 446 | label: player.localize('Copy the video URL at the current time'), |
433 | listener: function () { | 447 | listener: function () { |
434 | const player = this as videojs.Player | 448 | const player = this as videojs.Player |
435 | copyToClipboard(buildVideoLink(player.currentTime())) | 449 | copyToClipboard(buildVideoLink({ startTime: player.currentTime() })) |
436 | } | 450 | } |
437 | }, | 451 | }, |
438 | { | 452 | { |
diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts index 366689962..777abb568 100644 --- a/client/src/assets/player/utils.ts +++ b/client/src/assets/player/utils.ts | |||
@@ -27,18 +27,55 @@ function isMobile () { | |||
27 | return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) | 27 | return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) |
28 | } | 28 | } |
29 | 29 | ||
30 | function buildVideoLink (time?: number, url?: string) { | 30 | function buildVideoLink (options: { |
31 | if (!url) url = window.location.origin + window.location.pathname.replace('/embed/', '/watch/') | 31 | baseUrl?: string, |
32 | 32 | ||
33 | if (time) { | 33 | startTime?: number, |
34 | const timeInt = Math.floor(time) | 34 | stopTime?: number, |
35 | 35 | ||
36 | const params = new URLSearchParams(window.location.search) | 36 | subtitle?: string, |
37 | params.set('start', secondsToTime(timeInt)) | ||
38 | 37 | ||
39 | return url + '?' + params.toString() | 38 | loop?: boolean, |
39 | autoplay?: boolean, | ||
40 | muted?: boolean, | ||
41 | |||
42 | // Embed options | ||
43 | title?: boolean, | ||
44 | warningTitle?: boolean, | ||
45 | controls?: boolean | ||
46 | } = {}) { | ||
47 | const { baseUrl } = options | ||
48 | |||
49 | const url = baseUrl | ||
50 | ? baseUrl | ||
51 | : window.location.origin + window.location.pathname.replace('/embed/', '/watch/') | ||
52 | |||
53 | const params = new URLSearchParams(window.location.search) | ||
54 | |||
55 | if (options.startTime) { | ||
56 | const startTimeInt = Math.floor(options.startTime) | ||
57 | params.set('start', secondsToTime(startTimeInt)) | ||
58 | } | ||
59 | |||
60 | if (options.stopTime) { | ||
61 | const stopTimeInt = Math.floor(options.stopTime) | ||
62 | params.set('stop', secondsToTime(stopTimeInt)) | ||
40 | } | 63 | } |
41 | 64 | ||
65 | if (options.subtitle) params.set('subtitle', options.subtitle) | ||
66 | |||
67 | if (options.loop === true) params.set('loop', '1') | ||
68 | if (options.autoplay === true) params.set('autoplay', '1') | ||
69 | if (options.muted === true) params.set('muted', '1') | ||
70 | if (options.title === false) params.set('title', '0') | ||
71 | if (options.warningTitle === false) params.set('warningTitle', '0') | ||
72 | if (options.controls === false) params.set('controls', '0') | ||
73 | |||
74 | let hasParams = false | ||
75 | params.forEach(() => hasParams = true) | ||
76 | |||
77 | if (hasParams) return url + '?' + params.toString() | ||
78 | |||
42 | return url | 79 | return url |
43 | } | 80 | } |
44 | 81 | ||
diff --git a/client/src/assets/player/videojs-components/peertube-link-button.ts b/client/src/assets/player/videojs-components/peertube-link-button.ts index fed8ea33e..4d0ea37f5 100644 --- a/client/src/assets/player/videojs-components/peertube-link-button.ts +++ b/client/src/assets/player/videojs-components/peertube-link-button.ts | |||
@@ -16,7 +16,7 @@ class PeerTubeLinkButton extends Button { | |||
16 | } | 16 | } |
17 | 17 | ||
18 | updateHref () { | 18 | updateHref () { |
19 | this.el().setAttribute('href', buildVideoLink(this.player().currentTime())) | 19 | this.el().setAttribute('href', buildVideoLink({ startTime: this.player().currentTime() })) |
20 | } | 20 | } |
21 | 21 | ||
22 | handleClick () { | 22 | handleClick () { |
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss index d84766240..c64a8ebf8 100644 --- a/client/src/sass/application.scss +++ b/client/src/sass/application.scss | |||
@@ -12,6 +12,7 @@ $assets-path: '../assets/'; | |||
12 | @import './player/index'; | 12 | @import './player/index'; |
13 | @import './loading-bar'; | 13 | @import './loading-bar'; |
14 | 14 | ||
15 | @import './bootstrap'; | ||
15 | @import './primeng-custom'; | 16 | @import './primeng-custom'; |
16 | 17 | ||
17 | [hidden] { | 18 | [hidden] { |
@@ -181,128 +182,11 @@ label { | |||
181 | font-weight: bold; | 182 | font-weight: bold; |
182 | } | 183 | } |
183 | 184 | ||
184 | // Thanks https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d | ||
185 | .glyphicon-refresh-animate { | ||
186 | animation: spin .7s infinite linear; | ||
187 | } | ||
188 | |||
189 | @keyframes spin { | 185 | @keyframes spin { |
190 | from { transform: scale(1) rotate(0deg);} | 186 | from { transform: scale(1) rotate(0deg);} |
191 | to { transform: scale(1) rotate(360deg);} | 187 | to { transform: scale(1) rotate(360deg);} |
192 | } | 188 | } |
193 | 189 | ||
194 | // Bootstrap customizations | ||
195 | .dropdown-menu { | ||
196 | border-radius: 3px; | ||
197 | box-shadow: 0 3px 6px; | ||
198 | font-size: 15px; | ||
199 | |||
200 | .dropdown-item { | ||
201 | padding: 3px 15px; | ||
202 | |||
203 | &:active { | ||
204 | color: #000 !important; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | button { | ||
209 | @include disable-default-a-behaviour; | ||
210 | } | ||
211 | |||
212 | a { | ||
213 | @include disable-default-a-behaviour; | ||
214 | color: #000 !important; | ||
215 | } | ||
216 | } | ||
217 | |||
218 | .modal { | ||
219 | .modal-content { | ||
220 | background-color: var(--mainBackgroundColor); | ||
221 | } | ||
222 | |||
223 | .modal-header { | ||
224 | border-bottom: none; | ||
225 | margin-bottom: 5px; | ||
226 | |||
227 | .modal-title { | ||
228 | font-size: 20px; | ||
229 | font-weight: $font-semibold; | ||
230 | } | ||
231 | |||
232 | my-global-icon { | ||
233 | @include icon(24px); | ||
234 | |||
235 | position: relative; | ||
236 | top: 3px; | ||
237 | float: right; | ||
238 | |||
239 | margin: 0; | ||
240 | padding: 0; | ||
241 | opacity: 1; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | .inputs { | ||
246 | margin-bottom: 0; | ||
247 | text-align: right; | ||
248 | |||
249 | .action-button-cancel { | ||
250 | @include peertube-button; | ||
251 | @include grey-button; | ||
252 | |||
253 | display: inline-block; | ||
254 | margin-right: 10px; | ||
255 | } | ||
256 | |||
257 | .action-button-submit { | ||
258 | @include peertube-button; | ||
259 | @include orange-button; | ||
260 | } | ||
261 | } | ||
262 | } | ||
263 | |||
264 | // Nav customizations | ||
265 | .nav .nav-link { | ||
266 | display: flex !important; | ||
267 | align-items: center; | ||
268 | height: 30px !important; | ||
269 | padding: 10px 15px !important; | ||
270 | } | ||
271 | |||
272 | .nav.nav-pills { | ||
273 | font-size: 16px !important; | ||
274 | |||
275 | .nav-link.active { | ||
276 | font-weight: $font-semibold !important; | ||
277 | } | ||
278 | |||
279 | a { | ||
280 | @include disable-default-a-behaviour; | ||
281 | |||
282 | color: var(--mainForegroundColor); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | ngb-tabset.bootstrap { | ||
287 | |||
288 | .nav-link { | ||
289 | &, & a { | ||
290 | @include disable-default-a-behaviour; | ||
291 | |||
292 | color: var(--mainForegroundColor) !important; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | .nav-pills .nav-link.active { | ||
297 | color: #000 !important; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | .nav-tabs .nav-link.active { | ||
302 | background-color: var(--mainBackgroundColor) !important; | ||
303 | border-bottom: none; | ||
304 | } | ||
305 | |||
306 | .orange-button { | 190 | .orange-button { |
307 | @include peertube-button; | 191 | @include peertube-button; |
308 | @include orange-button; | 192 | @include orange-button; |
diff --git a/client/src/sass/bootstrap.scss b/client/src/sass/bootstrap.scss new file mode 100644 index 000000000..12e73278a --- /dev/null +++ b/client/src/sass/bootstrap.scss | |||
@@ -0,0 +1,138 @@ | |||
1 | $icon-font-path: '~@neos21/bootstrap3-glyphicons/assets/fonts/'; | ||
2 | @import '_bootstrap'; | ||
3 | |||
4 | @import '_variables'; | ||
5 | @import '_mixins'; | ||
6 | |||
7 | // Thanks https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d | ||
8 | .glyphicon-refresh-animate { | ||
9 | animation: spin .7s infinite linear; | ||
10 | } | ||
11 | |||
12 | @keyframes spin { | ||
13 | from { transform: scale(1) rotate(0deg);} | ||
14 | to { transform: scale(1) rotate(360deg);} | ||
15 | } | ||
16 | |||
17 | .dropdown-menu { | ||
18 | border-radius: 3px; | ||
19 | box-shadow: 0 3px 6px; | ||
20 | font-size: 15px; | ||
21 | |||
22 | .dropdown-item { | ||
23 | padding: 3px 15px; | ||
24 | |||
25 | &:active { | ||
26 | color: #000 !important; | ||
27 | } | ||
28 | } | ||
29 | |||
30 | button { | ||
31 | @include disable-default-a-behaviour; | ||
32 | } | ||
33 | |||
34 | a { | ||
35 | @include disable-default-a-behaviour; | ||
36 | color: #000 !important; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | .modal { | ||
41 | .modal-content { | ||
42 | background-color: var(--mainBackgroundColor); | ||
43 | } | ||
44 | |||
45 | .modal-header { | ||
46 | border-bottom: none; | ||
47 | margin-bottom: 5px; | ||
48 | |||
49 | .modal-title { | ||
50 | font-size: 20px; | ||
51 | font-weight: $font-semibold; | ||
52 | } | ||
53 | |||
54 | my-global-icon { | ||
55 | @include icon(24px); | ||
56 | |||
57 | position: relative; | ||
58 | top: 3px; | ||
59 | float: right; | ||
60 | |||
61 | margin: 0; | ||
62 | padding: 0; | ||
63 | opacity: 1; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | .inputs { | ||
68 | margin-bottom: 0; | ||
69 | text-align: right; | ||
70 | |||
71 | .action-button-cancel { | ||
72 | @include peertube-button; | ||
73 | @include grey-button; | ||
74 | |||
75 | display: inline-block; | ||
76 | margin-right: 10px; | ||
77 | } | ||
78 | |||
79 | .action-button-submit { | ||
80 | @include peertube-button; | ||
81 | @include orange-button; | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | // Nav customizations | ||
87 | .nav .nav-link { | ||
88 | display: flex !important; | ||
89 | align-items: center; | ||
90 | height: 30px !important; | ||
91 | padding: 10px 15px !important; | ||
92 | } | ||
93 | |||
94 | .nav.nav-pills { | ||
95 | font-size: 16px !important; | ||
96 | |||
97 | .nav-link.active { | ||
98 | font-weight: $font-semibold !important; | ||
99 | } | ||
100 | |||
101 | a { | ||
102 | @include disable-default-a-behaviour; | ||
103 | |||
104 | color: var(--mainForegroundColor); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | ngb-tabset.bootstrap { | ||
109 | |||
110 | .nav-link { | ||
111 | &, & a { | ||
112 | @include disable-default-a-behaviour; | ||
113 | |||
114 | color: var(--mainForegroundColor) !important; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | .nav-pills .nav-link.active { | ||
119 | color: #000 !important; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | .nav-tabs .nav-link.active { | ||
124 | background-color: var(--mainBackgroundColor) !important; | ||
125 | border-bottom: none; | ||
126 | } | ||
127 | |||
128 | .collapse-transition { | ||
129 | // Animation when we show/hide the filters | ||
130 | transition: max-height 0.3s; | ||
131 | display: block !important; | ||
132 | overflow: hidden !important; | ||
133 | max-height: 0; | ||
134 | |||
135 | &.show { | ||
136 | max-height: 1500px; | ||
137 | } | ||
138 | } | ||
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..f608e9299 100644 --- a/client/src/sass/include/_mixins.scss +++ b/client/src/sass/include/_mixins.scss | |||
@@ -235,6 +235,14 @@ | |||
235 | position: relative; | 235 | position: relative; |
236 | font-size: 15px; | 236 | font-size: 15px; |
237 | 237 | ||
238 | &.disabled { | ||
239 | background-color: #E5E5E5; | ||
240 | |||
241 | select { | ||
242 | cursor: default; | ||
243 | } | ||
244 | } | ||
245 | |||
238 | @media screen and (max-width: $width) { | 246 | @media screen and (max-width: $width) { |
239 | width: 100%; | 247 | width: 100%; |
240 | } | 248 | } |
@@ -282,16 +290,6 @@ | |||
282 | } | 290 | } |
283 | } | 291 | } |
284 | 292 | ||
285 | @mixin peertube-select-disabled-container ($width) { | ||
286 | @include peertube-select-container($width); | ||
287 | |||
288 | background-color: #E5E5E5; | ||
289 | |||
290 | select { | ||
291 | cursor: default; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | // Thanks: https://codepen.io/triss90/pen/XNEdRe/ | 293 | // Thanks: https://codepen.io/triss90/pen/XNEdRe/ |
296 | @mixin peertube-radio-container { | 294 | @mixin peertube-radio-container { |
297 | input[type="radio"] { | 295 | input[type="radio"] { |
@@ -331,7 +329,12 @@ | |||
331 | } | 329 | } |
332 | 330 | ||
333 | @mixin peertube-checkbox ($border-width) { | 331 | @mixin peertube-checkbox ($border-width) { |
334 | display: none; | 332 | opacity: 0; |
333 | position: absolute; | ||
334 | |||
335 | &:focus + span { | ||
336 | outline: 1px solid #1e5180; | ||
337 | } | ||
335 | 338 | ||
336 | & + span { | 339 | & + span { |
337 | position: relative; | 340 | position: relative; |
diff --git a/client/src/sass/include/_variables.scss b/client/src/sass/include/_variables.scss index c7b205b11..aafeda257 100644 --- a/client/src/sass/include/_variables.scss +++ b/client/src/sass/include/_variables.scss | |||
@@ -71,7 +71,9 @@ $variables: ( | |||
71 | --menuForegroundColor: var(--menuForegroundColor), | 71 | --menuForegroundColor: var(--menuForegroundColor), |
72 | --submenuColor: var(--submenuColor), | 72 | --submenuColor: var(--submenuColor), |
73 | --inputColor: var(--inputColor), | 73 | --inputColor: var(--inputColor), |
74 | --inputPlaceholderColor: var(--inputPlaceholderColor) | 74 | --inputPlaceholderColor: var(--inputPlaceholderColor), |
75 | --embedForegroundColor: var(--embedForegroundColor), | ||
76 | --embedBigPlayBackgroundColor: var(--embedBigPlayBackgroundColor) | ||
75 | ); | 77 | ); |
76 | 78 | ||
77 | /*** theme helper ***/ | 79 | /*** theme helper ***/ |
diff --git a/client/src/sass/player/_player-variables.scss b/client/src/sass/player/_player-variables.scss index 110129790..4e9e8736c 100644 --- a/client/src/sass/player/_player-variables.scss +++ b/client/src/sass/player/_player-variables.scss | |||
@@ -10,4 +10,10 @@ $slider-bg-color: lighten($primary-background-color, 33%); | |||
10 | 10 | ||
11 | $progress-margin: 10px; | 11 | $progress-margin: 10px; |
12 | 12 | ||
13 | $assets-path: '../../assets/' !default; \ No newline at end of file | 13 | $assets-path: '../../assets/' !default; |
14 | |||
15 | body { | ||
16 | --embedForegroundColor: #{$primary-foreground-color}; | ||
17 | |||
18 | --embedBigPlayBackgroundColor: #{$primary-background-color}; | ||
19 | } | ||
diff --git a/client/src/sass/player/context-menu.scss b/client/src/sass/player/context-menu.scss index 71d6d1b1d..eeab0ccdf 100644 --- a/client/src/sass/player/context-menu.scss +++ b/client/src/sass/player/context-menu.scss | |||
@@ -14,7 +14,7 @@ $context-menu-width: 350px; | |||
14 | 14 | ||
15 | .vjs-menu-content { | 15 | .vjs-menu-content { |
16 | opacity: $primary-foreground-opacity; | 16 | opacity: $primary-foreground-opacity; |
17 | color: $primary-foreground-color; | 17 | color: var(--embedForegroundCsolor); |
18 | font-size: $font-size !important; | 18 | font-size: $font-size !important; |
19 | font-weight: $font-semibold; | 19 | font-weight: $font-semibold; |
20 | } | 20 | } |
@@ -30,4 +30,4 @@ $context-menu-width: 350px; | |||
30 | background-color: rgba(255, 255, 255, 0.2); | 30 | background-color: rgba(255, 255, 255, 0.2); |
31 | } | 31 | } |
32 | } | 32 | } |
33 | } \ No newline at end of file | 33 | } |
diff --git a/client/src/sass/player/peertube-skin.scss b/client/src/sass/player/peertube-skin.scss index e63a2875c..996024ade 100644 --- a/client/src/sass/player/peertube-skin.scss +++ b/client/src/sass/player/peertube-skin.scss | |||
@@ -10,9 +10,8 @@ | |||
10 | } | 10 | } |
11 | 11 | ||
12 | .video-js.vjs-peertube-skin { | 12 | .video-js.vjs-peertube-skin { |
13 | |||
14 | font-size: $font-size; | 13 | font-size: $font-size; |
15 | color: $primary-foreground-color; | 14 | color: var(--embedForegroundColor); |
16 | 15 | ||
17 | .vjs-dock-text { | 16 | .vjs-dock-text { |
18 | padding-right: 10px; | 17 | padding-right: 10px; |
@@ -114,7 +113,7 @@ | |||
114 | .vjs-control-bar, | 113 | .vjs-control-bar, |
115 | .vjs-big-play-button, | 114 | .vjs-big-play-button, |
116 | .vjs-settings-dialog { | 115 | .vjs-settings-dialog { |
117 | background-color: rgba($primary-background-color, 0.5); | 116 | background-color: var(--embedBigPlayBackgroundColor); |
118 | } | 117 | } |
119 | 118 | ||
120 | .vjs-poster { | 119 | .vjs-poster { |
@@ -139,7 +138,8 @@ | |||
139 | .vjs-theater-control, | 138 | .vjs-theater-control, |
140 | .vjs-settings | 139 | .vjs-settings |
141 | { | 140 | { |
142 | color: $primary-foreground-color !important; | 141 | color: var(--embedForegroundColor) !important; |
142 | |||
143 | opacity: $primary-foreground-opacity; | 143 | opacity: $primary-foreground-opacity; |
144 | transition: opacity .1s; | 144 | transition: opacity .1s; |
145 | 145 | ||
@@ -151,7 +151,7 @@ | |||
151 | .vjs-current-time, | 151 | .vjs-current-time, |
152 | .vjs-duration, | 152 | .vjs-duration, |
153 | .vjs-peertube { | 153 | .vjs-peertube { |
154 | color: $primary-foreground-color; | 154 | color: var(--embedForegroundColor); |
155 | opacity: $primary-foreground-opacity; | 155 | opacity: $primary-foreground-opacity; |
156 | } | 156 | } |
157 | 157 | ||
@@ -171,7 +171,7 @@ | |||
171 | transition: none; | 171 | transition: none; |
172 | 172 | ||
173 | .vjs-play-progress { | 173 | .vjs-play-progress { |
174 | background: $primary-foreground-color; | 174 | background: var(--embedForegroundColor); |
175 | 175 | ||
176 | // Not display the circle if the progress is not hovered | 176 | // Not display the circle if the progress is not hovered |
177 | &::before { | 177 | &::before { |
diff --git a/client/src/sass/player/settings-menu.scss b/client/src/sass/player/settings-menu.scss index 61965c85e..83407b445 100644 --- a/client/src/sass/player/settings-menu.scss +++ b/client/src/sass/player/settings-menu.scss | |||
@@ -38,7 +38,7 @@ $setting-transition-easing: ease-out; | |||
38 | position: absolute; | 38 | position: absolute; |
39 | right: .5em; | 39 | right: .5em; |
40 | bottom: 3.5em; | 40 | bottom: 3.5em; |
41 | color: $primary-foreground-color; | 41 | color: var(--embedForegroundColor); |
42 | opacity: $primary-foreground-opacity; | 42 | opacity: $primary-foreground-opacity; |
43 | margin: 0 auto; | 43 | margin: 0 auto; |
44 | font-size: $font-size !important; | 44 | font-size: $font-size !important; |
diff --git a/client/src/standalone/videos/embed-api.ts b/client/src/standalone/videos/embed-api.ts new file mode 100644 index 000000000..169e371da --- /dev/null +++ b/client/src/standalone/videos/embed-api.ts | |||
@@ -0,0 +1,130 @@ | |||
1 | import './embed.scss' | ||
2 | |||
3 | import * as Channel from 'jschannel' | ||
4 | import { PeerTubeResolution } from '../player/definitions' | ||
5 | import { PeerTubeEmbed } from './embed' | ||
6 | |||
7 | /** | ||
8 | * Embed API exposes control of the embed player to the outside world via | ||
9 | * JSChannels and window.postMessage | ||
10 | */ | ||
11 | export class PeerTubeEmbedApi { | ||
12 | private channel: Channel.MessagingChannel | ||
13 | private isReady = false | ||
14 | private resolutions: PeerTubeResolution[] = null | ||
15 | |||
16 | constructor (private embed: PeerTubeEmbed) { | ||
17 | } | ||
18 | |||
19 | initialize () { | ||
20 | this.constructChannel() | ||
21 | this.setupStateTracking() | ||
22 | |||
23 | // We're ready! | ||
24 | |||
25 | this.notifyReady() | ||
26 | } | ||
27 | |||
28 | private get element () { | ||
29 | return this.embed.videoElement | ||
30 | } | ||
31 | |||
32 | private constructChannel () { | ||
33 | const channel = Channel.build({ window: window.parent, origin: '*', scope: this.embed.scope }) | ||
34 | |||
35 | channel.bind('play', (txn, params) => this.embed.player.play()) | ||
36 | channel.bind('pause', (txn, params) => this.embed.player.pause()) | ||
37 | channel.bind('seek', (txn, time) => this.embed.player.currentTime(time)) | ||
38 | channel.bind('setVolume', (txn, value) => this.embed.player.volume(value)) | ||
39 | channel.bind('getVolume', (txn, value) => this.embed.player.volume()) | ||
40 | channel.bind('isReady', (txn, params) => this.isReady) | ||
41 | channel.bind('setResolution', (txn, resolutionId) => this.setResolution(resolutionId)) | ||
42 | channel.bind('getResolutions', (txn, params) => this.resolutions) | ||
43 | channel.bind('setPlaybackRate', (txn, playbackRate) => this.embed.player.playbackRate(playbackRate)) | ||
44 | channel.bind('getPlaybackRate', (txn, params) => this.embed.player.playbackRate()) | ||
45 | channel.bind('getPlaybackRates', (txn, params) => this.embed.playerOptions.playbackRates) | ||
46 | |||
47 | this.channel = channel | ||
48 | } | ||
49 | |||
50 | private setResolution (resolutionId: number) { | ||
51 | if (resolutionId === -1 && this.embed.player.webtorrent().isAutoResolutionForbidden()) return | ||
52 | |||
53 | // Auto resolution | ||
54 | if (resolutionId === -1) { | ||
55 | this.embed.player.webtorrent().enableAutoResolution() | ||
56 | return | ||
57 | } | ||
58 | |||
59 | this.embed.player.webtorrent().disableAutoResolution() | ||
60 | this.embed.player.webtorrent().updateResolution(resolutionId) | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * Let the host know that we're ready to go! | ||
65 | */ | ||
66 | private notifyReady () { | ||
67 | this.isReady = true | ||
68 | this.channel.notify({ method: 'ready', params: true }) | ||
69 | } | ||
70 | |||
71 | private setupStateTracking () { | ||
72 | let currentState: 'playing' | 'paused' | 'unstarted' = 'unstarted' | ||
73 | |||
74 | setInterval(() => { | ||
75 | const position = this.element.currentTime | ||
76 | const volume = this.element.volume | ||
77 | |||
78 | this.channel.notify({ | ||
79 | method: 'playbackStatusUpdate', | ||
80 | params: { | ||
81 | position, | ||
82 | volume, | ||
83 | playbackState: currentState | ||
84 | } | ||
85 | }) | ||
86 | }, 500) | ||
87 | |||
88 | this.element.addEventListener('play', ev => { | ||
89 | currentState = 'playing' | ||
90 | this.channel.notify({ method: 'playbackStatusChange', params: 'playing' }) | ||
91 | }) | ||
92 | |||
93 | this.element.addEventListener('pause', ev => { | ||
94 | currentState = 'paused' | ||
95 | this.channel.notify({ method: 'playbackStatusChange', params: 'paused' }) | ||
96 | }) | ||
97 | |||
98 | // PeerTube specific capabilities | ||
99 | |||
100 | if (this.embed.player.webtorrent) { | ||
101 | this.embed.player.webtorrent().on('autoResolutionUpdate', () => this.loadWebTorrentResolutions()) | ||
102 | this.embed.player.webtorrent().on('videoFileUpdate', () => this.loadWebTorrentResolutions()) | ||
103 | } | ||
104 | } | ||
105 | |||
106 | private loadWebTorrentResolutions () { | ||
107 | const resolutions = [] | ||
108 | const currentResolutionId = this.embed.player.webtorrent().getCurrentResolutionId() | ||
109 | |||
110 | for (const videoFile of this.embed.player.webtorrent().videoFiles) { | ||
111 | let label = videoFile.resolution.label | ||
112 | if (videoFile.fps && videoFile.fps >= 50) { | ||
113 | label += videoFile.fps | ||
114 | } | ||
115 | |||
116 | resolutions.push({ | ||
117 | id: videoFile.resolution.id, | ||
118 | label, | ||
119 | src: videoFile.magnetUri, | ||
120 | active: videoFile.resolution.id === currentResolutionId | ||
121 | }) | ||
122 | } | ||
123 | |||
124 | this.resolutions = resolutions | ||
125 | this.channel.notify({ | ||
126 | method: 'resolutionUpdate', | ||
127 | params: this.resolutions | ||
128 | }) | ||
129 | } | ||
130 | } | ||
diff --git a/client/src/standalone/videos/embed.html b/client/src/standalone/videos/embed.html index c3b6e08ca..5a15bf552 100644 --- a/client/src/standalone/videos/embed.html +++ b/client/src/standalone/videos/embed.html | |||
@@ -11,7 +11,7 @@ | |||
11 | <link rel="icon" type="image/png" href="/client/assets/images/favicon.png" /> | 11 | <link rel="icon" type="image/png" href="/client/assets/images/favicon.png" /> |
12 | </head> | 12 | </head> |
13 | 13 | ||
14 | <body> | 14 | <body id="custom-css"> |
15 | 15 | ||
16 | <div id="error-block"> | 16 | <div id="error-block"> |
17 | <h1 id="error-title"></h1> | 17 | <h1 id="error-title"></h1> |
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index 707f04253..cfe8e94b1 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts | |||
@@ -1,9 +1,6 @@ | |||
1 | import './embed.scss' | 1 | import './embed.scss' |
2 | 2 | ||
3 | import * as Channel from 'jschannel' | ||
4 | |||
5 | import { peertubeTranslate, ResultList, ServerConfig, VideoDetails } from '../../../../shared' | 3 | import { peertubeTranslate, ResultList, ServerConfig, VideoDetails } from '../../../../shared' |
6 | import { PeerTubeResolution } from '../player/definitions' | ||
7 | import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings' | 4 | import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings' |
8 | import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model' | 5 | import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model' |
9 | import { | 6 | import { |
@@ -13,133 +10,9 @@ import { | |||
13 | PlayerMode | 10 | PlayerMode |
14 | } from '../../assets/player/peertube-player-manager' | 11 | } from '../../assets/player/peertube-player-manager' |
15 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' | 12 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' |
13 | import { PeerTubeEmbedApi } from './embed-api' | ||
16 | 14 | ||
17 | /** | 15 | export class PeerTubeEmbed { |
18 | * Embed API exposes control of the embed player to the outside world via | ||
19 | * JSChannels and window.postMessage | ||
20 | */ | ||
21 | class PeerTubeEmbedApi { | ||
22 | private channel: Channel.MessagingChannel | ||
23 | private isReady = false | ||
24 | private resolutions: PeerTubeResolution[] = null | ||
25 | |||
26 | constructor (private embed: PeerTubeEmbed) { | ||
27 | } | ||
28 | |||
29 | initialize () { | ||
30 | this.constructChannel() | ||
31 | this.setupStateTracking() | ||
32 | |||
33 | // We're ready! | ||
34 | |||
35 | this.notifyReady() | ||
36 | } | ||
37 | |||
38 | private get element () { | ||
39 | return this.embed.videoElement | ||
40 | } | ||
41 | |||
42 | private constructChannel () { | ||
43 | const channel = Channel.build({ window: window.parent, origin: '*', scope: this.embed.scope }) | ||
44 | |||
45 | channel.bind('play', (txn, params) => this.embed.player.play()) | ||
46 | channel.bind('pause', (txn, params) => this.embed.player.pause()) | ||
47 | channel.bind('seek', (txn, time) => this.embed.player.currentTime(time)) | ||
48 | channel.bind('setVolume', (txn, value) => this.embed.player.volume(value)) | ||
49 | channel.bind('getVolume', (txn, value) => this.embed.player.volume()) | ||
50 | channel.bind('isReady', (txn, params) => this.isReady) | ||
51 | channel.bind('setResolution', (txn, resolutionId) => this.setResolution(resolutionId)) | ||
52 | channel.bind('getResolutions', (txn, params) => this.resolutions) | ||
53 | channel.bind('setPlaybackRate', (txn, playbackRate) => this.embed.player.playbackRate(playbackRate)) | ||
54 | channel.bind('getPlaybackRate', (txn, params) => this.embed.player.playbackRate()) | ||
55 | channel.bind('getPlaybackRates', (txn, params) => this.embed.playerOptions.playbackRates) | ||
56 | |||
57 | this.channel = channel | ||
58 | } | ||
59 | |||
60 | private setResolution (resolutionId: number) { | ||
61 | if (resolutionId === -1 && this.embed.player.webtorrent().isAutoResolutionForbidden()) return | ||
62 | |||
63 | // Auto resolution | ||
64 | if (resolutionId === -1) { | ||
65 | this.embed.player.webtorrent().enableAutoResolution() | ||
66 | return | ||
67 | } | ||
68 | |||
69 | this.embed.player.webtorrent().disableAutoResolution() | ||
70 | this.embed.player.webtorrent().updateResolution(resolutionId) | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * Let the host know that we're ready to go! | ||
75 | */ | ||
76 | private notifyReady () { | ||
77 | this.isReady = true | ||
78 | this.channel.notify({ method: 'ready', params: true }) | ||
79 | } | ||
80 | |||
81 | private setupStateTracking () { | ||
82 | let currentState: 'playing' | 'paused' | 'unstarted' = 'unstarted' | ||
83 | |||
84 | setInterval(() => { | ||
85 | const position = this.element.currentTime | ||
86 | const volume = this.element.volume | ||
87 | |||
88 | this.channel.notify({ | ||
89 | method: 'playbackStatusUpdate', | ||
90 | params: { | ||
91 | position, | ||
92 | volume, | ||
93 | playbackState: currentState | ||
94 | } | ||
95 | }) | ||
96 | }, 500) | ||
97 | |||
98 | this.element.addEventListener('play', ev => { | ||
99 | currentState = 'playing' | ||
100 | this.channel.notify({ method: 'playbackStatusChange', params: 'playing' }) | ||
101 | }) | ||
102 | |||
103 | this.element.addEventListener('pause', ev => { | ||
104 | currentState = 'paused' | ||
105 | this.channel.notify({ method: 'playbackStatusChange', params: 'paused' }) | ||
106 | }) | ||
107 | |||
108 | // PeerTube specific capabilities | ||
109 | |||
110 | if (this.embed.player.webtorrent) { | ||
111 | this.embed.player.webtorrent().on('autoResolutionUpdate', () => this.loadWebTorrentResolutions()) | ||
112 | this.embed.player.webtorrent().on('videoFileUpdate', () => this.loadWebTorrentResolutions()) | ||
113 | } | ||
114 | } | ||
115 | |||
116 | private loadWebTorrentResolutions () { | ||
117 | const resolutions = [] | ||
118 | const currentResolutionId = this.embed.player.webtorrent().getCurrentResolutionId() | ||
119 | |||
120 | for (const videoFile of this.embed.player.webtorrent().videoFiles) { | ||
121 | let label = videoFile.resolution.label | ||
122 | if (videoFile.fps && videoFile.fps >= 50) { | ||
123 | label += videoFile.fps | ||
124 | } | ||
125 | |||
126 | resolutions.push({ | ||
127 | id: videoFile.resolution.id, | ||
128 | label, | ||
129 | src: videoFile.magnetUri, | ||
130 | active: videoFile.resolution.id === currentResolutionId | ||
131 | }) | ||
132 | } | ||
133 | |||
134 | this.resolutions = resolutions | ||
135 | this.channel.notify({ | ||
136 | method: 'resolutionUpdate', | ||
137 | params: this.resolutions | ||
138 | }) | ||
139 | } | ||
140 | } | ||
141 | |||
142 | class PeerTubeEmbed { | ||
143 | videoElement: HTMLVideoElement | 16 | videoElement: HTMLVideoElement |
144 | player: any | 17 | player: any |
145 | playerOptions: any | 18 | playerOptions: any |
@@ -152,6 +25,12 @@ class PeerTubeEmbed { | |||
152 | enableApi = false | 25 | enableApi = false |
153 | startTime: number | string = 0 | 26 | startTime: number | string = 0 |
154 | stopTime: number | string | 27 | stopTime: number | string |
28 | |||
29 | title: boolean | ||
30 | warningTitle: boolean | ||
31 | bigPlayBackgroundColor: string | ||
32 | foregroundColor: string | ||
33 | |||
155 | mode: PlayerMode | 34 | mode: PlayerMode |
156 | scope = 'peertube' | 35 | scope = 'peertube' |
157 | 36 | ||
@@ -245,13 +124,18 @@ class PeerTubeEmbed { | |||
245 | this.controls = this.getParamToggle(params, 'controls', true) | 124 | this.controls = this.getParamToggle(params, 'controls', true) |
246 | this.muted = this.getParamToggle(params, 'muted', false) | 125 | this.muted = this.getParamToggle(params, 'muted', false) |
247 | this.loop = this.getParamToggle(params, 'loop', false) | 126 | this.loop = this.getParamToggle(params, 'loop', false) |
127 | this.title = this.getParamToggle(params, 'title', true) | ||
248 | this.enableApi = this.getParamToggle(params, 'api', this.enableApi) | 128 | this.enableApi = this.getParamToggle(params, 'api', this.enableApi) |
129 | this.warningTitle = this.getParamToggle(params, 'warningTitle', true) | ||
249 | 130 | ||
250 | this.scope = this.getParamString(params, 'scope', this.scope) | 131 | this.scope = this.getParamString(params, 'scope', this.scope) |
251 | this.subtitle = this.getParamString(params, 'subtitle') | 132 | this.subtitle = this.getParamString(params, 'subtitle') |
252 | this.startTime = this.getParamString(params, 'start') | 133 | this.startTime = this.getParamString(params, 'start') |
253 | this.stopTime = this.getParamString(params, 'stop') | 134 | this.stopTime = this.getParamString(params, 'stop') |
254 | 135 | ||
136 | this.bigPlayBackgroundColor = this.getParamString(params, 'bigPlayBackgroundColor') | ||
137 | this.foregroundColor = this.getParamString(params, 'foregroundColor') | ||
138 | |||
255 | this.mode = this.getParamString(params, 'mode') === 'p2p-media-loader' ? 'p2p-media-loader' : 'webtorrent' | 139 | this.mode = this.getParamString(params, 'mode') === 'p2p-media-loader' ? 'p2p-media-loader' : 'webtorrent' |
256 | } catch (err) { | 140 | } catch (err) { |
257 | console.error('Cannot get params from URL.', err) | 141 | console.error('Cannot get params from URL.', err) |
@@ -276,15 +160,7 @@ class PeerTubeEmbed { | |||
276 | } | 160 | } |
277 | 161 | ||
278 | const videoInfo: VideoDetails = await videoResponse.json() | 162 | const videoInfo: VideoDetails = await videoResponse.json() |
279 | let videoCaptions: VideoJSCaption[] = [] | 163 | const videoCaptions = await this.buildCaptions(serverTranslations, captionsResponse) |
280 | if (captionsResponse.ok) { | ||
281 | const { data } = (await captionsResponse.json()) as ResultList<VideoCaption> | ||
282 | videoCaptions = data.map(c => ({ | ||
283 | label: peertubeTranslate(c.language.label, serverTranslations), | ||
284 | language: c.language.id, | ||
285 | src: window.location.origin + c.captionPath | ||
286 | })) | ||
287 | } | ||
288 | 164 | ||
289 | this.loadParams() | 165 | this.loadParams() |
290 | 166 | ||
@@ -337,33 +213,66 @@ class PeerTubeEmbed { | |||
337 | } | 213 | } |
338 | 214 | ||
339 | this.player = await PeertubePlayerManager.initialize(this.mode, options) | 215 | this.player = await PeertubePlayerManager.initialize(this.mode, options) |
340 | |||
341 | this.player.on('customError', (event: any, data: any) => this.handleError(data.err, serverTranslations)) | 216 | this.player.on('customError', (event: any, data: any) => this.handleError(data.err, serverTranslations)) |
342 | 217 | ||
343 | window[ 'videojsPlayer' ] = this.player | 218 | window[ 'videojsPlayer' ] = this.player |
344 | 219 | ||
220 | this.buildCSS() | ||
221 | |||
222 | await this.buildDock(videoInfo, configResponse) | ||
223 | |||
224 | this.initializeApi() | ||
225 | } | ||
226 | |||
227 | private handleError (err: Error, translations?: { [ id: string ]: string }) { | ||
228 | if (err.message.indexOf('from xs param') !== -1) { | ||
229 | this.player.dispose() | ||
230 | this.videoElement = null | ||
231 | this.displayError('This video is not available because the remote instance is not responding.', translations) | ||
232 | return | ||
233 | } | ||
234 | } | ||
235 | |||
236 | private async buildDock (videoInfo: VideoDetails, configResponse: Response) { | ||
345 | if (this.controls) { | 237 | if (this.controls) { |
238 | const title = this.title ? videoInfo.name : undefined | ||
239 | |||
346 | const config: ServerConfig = await configResponse.json() | 240 | const config: ServerConfig = await configResponse.json() |
347 | const description = config.tracker.enabled | 241 | const description = config.tracker.enabled && this.warningTitle |
348 | ? '<span class="text">' + this.player.localize('Uses P2P, others may know your IP is downloading this video.') + '</span>' | 242 | ? '<span class="text">' + this.player.localize('Uses P2P, others may know your IP is downloading this video.') + '</span>' |
349 | : undefined | 243 | : undefined |
350 | 244 | ||
351 | this.player.dock({ | 245 | this.player.dock({ |
352 | title: videoInfo.name, | 246 | title, |
353 | description | 247 | description |
354 | }) | 248 | }) |
355 | } | 249 | } |
250 | } | ||
356 | 251 | ||
357 | this.initializeApi() | 252 | private buildCSS () { |
253 | const body = document.getElementById('custom-css') | ||
254 | |||
255 | if (this.bigPlayBackgroundColor) { | ||
256 | body.style.setProperty('--embedBigPlayBackgroundColor', this.bigPlayBackgroundColor) | ||
257 | } | ||
258 | |||
259 | if (this.foregroundColor) { | ||
260 | body.style.setProperty('--embedForegroundColor', this.foregroundColor) | ||
261 | } | ||
358 | } | 262 | } |
359 | 263 | ||
360 | private handleError (err: Error, translations?: { [ id: string ]: string }) { | 264 | private async buildCaptions (serverTranslations: any, captionsResponse: Response): Promise<VideoJSCaption[]> { |
361 | if (err.message.indexOf('from xs param') !== -1) { | 265 | if (captionsResponse.ok) { |
362 | this.player.dispose() | 266 | const { data } = (await captionsResponse.json()) as ResultList<VideoCaption> |
363 | this.videoElement = null | 267 | |
364 | this.displayError('This video is not available because the remote instance is not responding.', translations) | 268 | return data.map(c => ({ |
365 | return | 269 | label: peertubeTranslate(c.language.label, serverTranslations), |
270 | language: c.language.id, | ||
271 | src: window.location.origin + c.captionPath | ||
272 | })) | ||
366 | } | 273 | } |
274 | |||
275 | return [] | ||
367 | } | 276 | } |
368 | } | 277 | } |
369 | 278 | ||
diff --git a/config/default.yaml b/config/default.yaml index 37ef4366f..a213d5b0a 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 | ||
56 | email: | ||
57 | body: | ||
58 | signature: "PeerTube" | ||
59 | object: | ||
60 | prefix: "[PeerTube]" | ||
61 | |||
56 | # From the project root directory | 62 | # From the project root directory |
57 | storage: | 63 | storage: |
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... |
@@ -69,6 +75,8 @@ storage: | |||
69 | 75 | ||
70 | log: | 76 | log: |
71 | level: 'info' # debug/info/warning/error | 77 | level: 'info' # debug/info/warning/error |
78 | rotation: | ||
79 | enabled : true # Enabled by default, if disabled make sure that 'storage.logs' is pointing to a folder handled by logrotate | ||
72 | 80 | ||
73 | search: | 81 | search: |
74 | # Add ability to fetch remote videos/actors by their URI, that may not be federated with your instance | 82 | # Add ability to fetch remote videos/actors by their URI, that may not be federated with your instance |
@@ -174,6 +182,8 @@ transcoding: | |||
174 | enabled: true | 182 | enabled: true |
175 | # Allow your users to upload .mkv, .mov, .avi, .flv videos | 183 | # Allow your users to upload .mkv, .mov, .avi, .flv videos |
176 | allow_additional_extensions: true | 184 | allow_additional_extensions: true |
185 | # If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file | ||
186 | allow_audio_files: true | ||
177 | threads: 1 | 187 | threads: 1 |
178 | resolutions: # Only created if the original video has a higher resolution, uses more storage! | 188 | resolutions: # Only created if the original video has a higher resolution, uses more storage! |
179 | 240p: false | 189 | 240p: false |
@@ -181,6 +191,7 @@ transcoding: | |||
181 | 480p: false | 191 | 480p: false |
182 | 720p: false | 192 | 720p: false |
183 | 1080p: false | 193 | 1080p: false |
194 | 2160p: false | ||
184 | # /!\ EXPERIMENTAL /!\ | 195 | # /!\ EXPERIMENTAL /!\ |
185 | # /!\ Requires ffmpeg >= 4 | 196 | # /!\ Requires ffmpeg >= 4 |
186 | # Generate HLS playlists and fragmented MP4 files. Better playback than with WebTorrent: | 197 | # 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..cdf6136d8 100644 --- a/config/production.yaml.example +++ b/config/production.yaml.example | |||
@@ -54,6 +54,12 @@ smtp: | |||
54 | ca_file: null # Used for self signed certificates | 54 | ca_file: null # Used for self signed certificates |
55 | from_address: 'admin@example.com' | 55 | from_address: 'admin@example.com' |
56 | 56 | ||
57 | email: | ||
58 | body: | ||
59 | signature: "PeerTube" | ||
60 | object: | ||
61 | prefix: "[PeerTube]" | ||
62 | |||
57 | # From the project root directory | 63 | # From the project root directory |
58 | storage: | 64 | storage: |
59 | tmp: '/var/www/peertube/storage/tmp/' # Used to download data (imports etc), store uploaded files before processing... | 65 | tmp: '/var/www/peertube/storage/tmp/' # Used to download data (imports etc), store uploaded files before processing... |
@@ -70,6 +76,8 @@ storage: | |||
70 | 76 | ||
71 | log: | 77 | log: |
72 | level: 'info' # debug/info/warning/error | 78 | level: 'info' # debug/info/warning/error |
79 | rotation: | ||
80 | enabled : true | ||
73 | 81 | ||
74 | search: | 82 | search: |
75 | # Add ability to fetch remote videos/actors by their URI, that may not be federated with your instance | 83 | # Add ability to fetch remote videos/actors by their URI, that may not be federated with your instance |
@@ -188,6 +196,8 @@ transcoding: | |||
188 | enabled: true | 196 | enabled: true |
189 | # Allow your users to upload .mkv, .mov, .avi, .flv videos | 197 | # Allow your users to upload .mkv, .mov, .avi, .flv videos |
190 | allow_additional_extensions: true | 198 | allow_additional_extensions: true |
199 | # If a user uploads an audio file, PeerTube will create a video by merging the preview file and the audio file | ||
200 | allow_audio_files: true | ||
191 | threads: 1 | 201 | threads: 1 |
192 | resolutions: # Only created if the original video has a higher resolution, uses more storage! | 202 | resolutions: # Only created if the original video has a higher resolution, uses more storage! |
193 | 240p: false | 203 | 240p: false |
@@ -195,6 +205,7 @@ transcoding: | |||
195 | 480p: false | 205 | 480p: false |
196 | 720p: false | 206 | 720p: false |
197 | 1080p: false | 207 | 1080p: false |
208 | 2160p: false | ||
198 | # /!\ EXPERIMENTAL /!\ | 209 | # /!\ EXPERIMENTAL /!\ |
199 | # /!\ Requires ffmpeg >= 4 | 210 | # /!\ Requires ffmpeg >= 4 |
200 | # Generate HLS playlists and fragmented MP4 files. Better playback than with WebTorrent: | 211 | # Generate HLS playlists and fragmented MP4 files. Better playback than with WebTorrent: |
@@ -245,8 +256,6 @@ instance: | |||
245 | "# If you would like to report a security issue\n# you may report it to:\nContact: https://github.com/Chocobozzz/PeerTube/blob/develop/SECURITY.md\nContact: mailto:" | 256 | "# If you would like to report a security issue\n# you may report it to:\nContact: https://github.com/Chocobozzz/PeerTube/blob/develop/SECURITY.md\nContact: mailto:" |
246 | 257 | ||
247 | services: | 258 | services: |
248 | # You can provide a reporting endpoint for Content Security Policy violations | ||
249 | csp-logger: | ||
250 | # Cards configuration to format video in Twitter | 259 | # Cards configuration to format video in Twitter |
251 | twitter: | 260 | twitter: |
252 | username: '@Chocobozzz' # Indicates the Twitter account for the website or platform on which the content was published | 261 | username: '@Chocobozzz' # Indicates the Twitter account for the website or platform on which the content was published |
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: | |||
31 | transcoding: | 31 | transcoding: |
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: | |||
55 | transcoding: | 55 | transcoding: |
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 3846b45fa..ee12718c7 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", |
@@ -56,6 +57,7 @@ | |||
56 | "postinstall": "test -n \"$NOCLIENT\" || (cd client && yarn install --pure-lockfile)", | 57 | "postinstall": "test -n \"$NOCLIENT\" || (cd client && yarn install --pure-lockfile)", |
57 | "tsc": "tsc", | 58 | "tsc": "tsc", |
58 | "commander": "commander", | 59 | "commander": "commander", |
60 | "lint": "npm run travis -- lint", | ||
59 | "ng": "ng", | 61 | "ng": "ng", |
60 | "nodemon": "nodemon", | 62 | "nodemon": "nodemon", |
61 | "ts-node": "ts-node", | 63 | "ts-node": "ts-node", |
@@ -92,18 +94,15 @@ | |||
92 | }, | 94 | }, |
93 | "dependencies": { | 95 | "dependencies": { |
94 | "apicache": "^1.4.0", | 96 | "apicache": "^1.4.0", |
95 | "application-config": "^1.0.1", | 97 | "async": "^3.0.1", |
96 | "async": "^2.0.0", | ||
97 | "async-lru": "^1.1.1", | 98 | "async-lru": "^1.1.1", |
98 | "bcrypt": "3.0.5", | 99 | "bcrypt": "3.0.6", |
99 | "bittorrent-tracker": "^9.0.0", | 100 | "bittorrent-tracker": "^9.0.0", |
100 | "bluebird": "^3.5.0", | 101 | "bluebird": "^3.5.0", |
101 | "body-parser": "^1.12.4", | 102 | "body-parser": "^1.12.4", |
102 | "bull": "^3.4.2", | 103 | "bull": "^3.4.2", |
103 | "bytes": "^3.0.0", | 104 | "bytes": "^3.0.0", |
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", |
@@ -130,7 +129,6 @@ | |||
130 | "memoizee": "^0.4.14", | 129 | "memoizee": "^0.4.14", |
131 | "morgan": "^1.5.3", | 130 | "morgan": "^1.5.3", |
132 | "multer": "^1.1.0", | 131 | "multer": "^1.1.0", |
133 | "netrc-parser": "^3.1.6", | ||
134 | "nodemailer": "^6.0.0", | 132 | "nodemailer": "^6.0.0", |
135 | "parse-torrent": "^6.0.0", | 133 | "parse-torrent": "^6.0.0", |
136 | "password-generator": "^2.0.2", | 134 | "password-generator": "^2.0.2", |
@@ -142,25 +140,24 @@ | |||
142 | "reflect-metadata": "^0.1.12", | 140 | "reflect-metadata": "^0.1.12", |
143 | "request": "^2.81.0", | 141 | "request": "^2.81.0", |
144 | "scripty": "^1.5.0", | 142 | "scripty": "^1.5.0", |
145 | "sequelize": "5.7.4", | 143 | "sequelize": "5.8.7", |
146 | "sequelize-typescript": "1.0.0-beta.2", | 144 | "sequelize-typescript": "1.0.0-beta.2", |
147 | "sharp": "^0.22.0", | 145 | "sharp": "^0.22.0", |
148 | "sitemap": "^2.1.0", | 146 | "sitemap": "^2.1.0", |
149 | "socket.io": "^2.2.0", | 147 | "socket.io": "^2.2.0", |
150 | "srt-to-vtt": "^1.1.2", | 148 | "srt-to-vtt": "^1.1.2", |
151 | "summon-install": "^0.4.3", | ||
152 | "useragent": "^2.3.0", | 149 | "useragent": "^2.3.0", |
153 | "uuid": "^3.1.0", | 150 | "uuid": "^3.1.0", |
154 | "validator": "^10.2.0", | 151 | "validator": "^11.0.0", |
155 | "webfinger.js": "^2.6.6", | 152 | "webfinger.js": "^2.6.6", |
156 | "webtorrent": "^0.103.0", | 153 | "webtorrent": "^0.103.0", |
157 | "winston": "3.2.1", | 154 | "winston": "3.2.1", |
158 | "ws": "^6.0.0", | 155 | "ws": "^7.0.0", |
159 | "youtube-dl": "^1.12.2" | 156 | "youtube-dl": "^2.0.0" |
160 | }, | 157 | }, |
161 | "devDependencies": { | 158 | "devDependencies": { |
162 | "@types/apicache": "^1.2.0", | 159 | "@types/apicache": "^1.2.0", |
163 | "@types/async": "^2.0.40", | 160 | "@types/async": "^3.0.0", |
164 | "@types/async-lock": "^1.1.0", | 161 | "@types/async-lock": "^1.1.0", |
165 | "@types/bcrypt": "^3.0.0", | 162 | "@types/bcrypt": "^3.0.0", |
166 | "@types/bluebird": "3.5.21", | 163 | "@types/bluebird": "3.5.21", |
@@ -174,7 +171,7 @@ | |||
174 | "@types/express": "^4.0.35", | 171 | "@types/express": "^4.0.35", |
175 | "@types/express-rate-limit": "^3.3.0", | 172 | "@types/express-rate-limit": "^3.3.0", |
176 | "@types/fluent-ffmpeg": "^2.1.8", | 173 | "@types/fluent-ffmpeg": "^2.1.8", |
177 | "@types/fs-extra": "^5.0.4", | 174 | "@types/fs-extra": "^7.0.0", |
178 | "@types/libxmljs": "^0.18.0", | 175 | "@types/libxmljs": "^0.18.0", |
179 | "@types/lodash": "^4.14.64", | 176 | "@types/lodash": "^4.14.64", |
180 | "@types/magnet-uri": "^5.1.1", | 177 | "@types/magnet-uri": "^5.1.1", |
@@ -185,7 +182,7 @@ | |||
185 | "@types/morgan": "^1.7.32", | 182 | "@types/morgan": "^1.7.32", |
186 | "@types/multer": "^1.3.3", | 183 | "@types/multer": "^1.3.3", |
187 | "@types/node": "^10.0.8", | 184 | "@types/node": "^10.0.8", |
188 | "@types/nodemailer": "^4.3.1", | 185 | "@types/nodemailer": "^6.2.0", |
189 | "@types/oauth2-server": "^3.0.8", | 186 | "@types/oauth2-server": "^3.0.8", |
190 | "@types/pem": "^1.9.3", | 187 | "@types/pem": "^1.9.3", |
191 | "@types/redis": "^2.8.5", | 188 | "@types/redis": "^2.8.5", |
@@ -199,18 +196,20 @@ | |||
199 | "chai": "^4.1.1", | 196 | "chai": "^4.1.1", |
200 | "chai-json-schema": "^1.5.0", | 197 | "chai-json-schema": "^1.5.0", |
201 | "chai-xml": "^0.3.2", | 198 | "chai-xml": "^0.3.2", |
202 | "husky": "^1.0.0-rc.4", | 199 | "concurrently": "^4.1.0", |
200 | "husky": "^2.4.0", | ||
203 | "libxmljs": "0.19.5", | 201 | "libxmljs": "0.19.5", |
204 | "lint-staged": "^8.0.4", | 202 | "lint-staged": "^8.0.4", |
205 | "maildev": "^1.0.0-rc3", | 203 | "maildev": "^1.0.0-rc3", |
206 | "marked-man": "^0.4.2", | 204 | "marked-man": "^0.6.0", |
207 | "mocha": "^6.0.0", | 205 | "mocha": "^6.0.0", |
206 | "mocha-parallel-tests": "^2.1.0", | ||
208 | "nodemon": "^1.18.6", | 207 | "nodemon": "^1.18.6", |
209 | "sass-lint": "^1.12.1", | 208 | "sass-lint": "^1.12.1", |
210 | "source-map-support": "^0.5.0", | 209 | "source-map-support": "^0.5.0", |
211 | "supertest": "^4.0.2", | 210 | "supertest": "^4.0.2", |
212 | "swagger-cli": "^2.2.0", | 211 | "swagger-cli": "^2.2.0", |
213 | "ts-node": "8.0.3", | 212 | "ts-node": "8.2.0", |
214 | "tslint": "^5.7.0", | 213 | "tslint": "^5.7.0", |
215 | "tslint-config-standard": "^8.0.1", | 214 | "tslint-config-standard": "^8.0.1", |
216 | "typescript": "^3.4.3", | 215 | "typescript": "^3.4.3", |
@@ -219,8 +218,5 @@ | |||
219 | "scripty": { | 218 | "scripty": { |
220 | "silent": true | 219 | "silent": true |
221 | }, | 220 | }, |
222 | "summon": { | ||
223 | "silent": true | ||
224 | }, | ||
225 | "sasslintConfig": "client/.sass-lint.yml" | 221 | "sasslintConfig": "client/.sass-lint.yml" |
226 | } | 222 | } |
diff --git a/scripts/clean/server/test.sh b/scripts/clean/server/test.sh index 5694ac922..20745170d 100755 --- a/scripts/clean/server/test.sh +++ b/scripts/clean/server/test.sh | |||
@@ -13,12 +13,15 @@ recreateDB () { | |||
13 | } | 13 | } |
14 | 14 | ||
15 | removeFiles () { | 15 | removeFiles () { |
16 | rm -rf "./test$1" "./config/local-test.json" "./config/local-test-$1.json" | 16 | rm -rf "./test$1" "./config/local-test.json" "./config/local-test-$1.json" ~/.config/PeerTube/CLI-$1 |
17 | } | 17 | } |
18 | 18 | ||
19 | dropRedis () { | 19 | dropRedis () { |
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 | ||
24 | seq=$(seq 1 6) | 27 | seq=$(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' | |||
2 | import { VideoModel } from '../server/models/video/video' | 2 | import { VideoModel } from '../server/models/video/video' |
3 | import { initDatabaseModels } from '../server/initializers' | 3 | import { initDatabaseModels } from '../server/initializers' |
4 | import { JobQueue } from '../server/lib/job-queue' | 4 | import { JobQueue } from '../server/lib/job-queue' |
5 | import { VideoTranscodingPayload } from '../server/lib/job-queue/handlers/video-transcoding' | ||
5 | 6 | ||
6 | program | 7 | program |
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..f761d7f8a --- /dev/null +++ b/scripts/setup/cli.sh | |||
@@ -0,0 +1,15 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | set -eu | ||
4 | |||
5 | NOCLIENT=1 yarn install --pure-lockfile | ||
6 | |||
7 | rm -rf ./dist/server/tools/ | ||
8 | |||
9 | ( | ||
10 | cd ./server/tools | ||
11 | yarn install --pure-lockfile | ||
12 | ) | ||
13 | |||
14 | npm run tsc -- --build ./server/tools/tsconfig.json | ||
15 | cp -r "./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 @@ | |||
3 | set -eu | 3 | set -eu |
4 | 4 | ||
5 | npm run build:server | 5 | npm run build:server |
6 | npm run setup:cli | ||
7 | |||
6 | npm run travis -- lint | 8 | npm run travis -- lint |
7 | 9 | ||
8 | mocha --exit --require ts-node/register/type-check --bail server/tests/index.ts | 10 | mocha --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 |
18 | elif [ "$1" = "cli" ]; then | 18 | elif [ "$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 |
21 | elif [ "$1" = "api-1" ]; then | 22 | elif [ "$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 |
24 | elif [ "$1" = "api-2" ]; then | 25 | elif [ "$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 |
27 | elif [ "$1" = "api-3" ]; then | 28 | elif [ "$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 |
30 | elif [ "$1" = "api-4" ]; then | 31 | elif [ "$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 |
33 | elif [ "$1" = "lint" ]; then | 34 | elif [ "$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' |
21 | import { AccountModel } from '../../models/account/account' | 22 | import { AccountModel } from '../../models/account/account' |
22 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' | 23 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' |
@@ -56,6 +57,10 @@ accountsRouter.get('/:accountName/videos', | |||
56 | 57 | ||
57 | accountsRouter.get('/:accountName/video-channels', | 58 | accountsRouter.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 | ||
110 | async function listAccountChannels (req: express.Request, res: express.Response) { | 115 | async 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..1d12f701b 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,13 +255,15 @@ 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' ], |
261 | '360p': CONFIG.TRANSCODING.RESOLUTIONS[ '360p' ], | 262 | '360p': CONFIG.TRANSCODING.RESOLUTIONS[ '360p' ], |
262 | '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ], | 263 | '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ], |
263 | '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ], | 264 | '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ], |
264 | '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ] | 265 | '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ], |
266 | '2160p': CONFIG.TRANSCODING.RESOLUTIONS[ '2160p' ] | ||
265 | }, | 267 | }, |
266 | hls: { | 268 | hls: { |
267 | enabled: CONFIG.TRANSCODING.HLS.ENABLED | 269 | enabled: CONFIG.TRANSCODING.HLS.ENABLED |
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index 0aafba66e..c1d72087c 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts | |||
@@ -6,7 +6,7 @@ import { getFormattedObjects } from '../../../helpers/utils' | |||
6 | import { RATES_LIMIT, WEBSERVER } from '../../../initializers/constants' | 6 | import { RATES_LIMIT, WEBSERVER } from '../../../initializers/constants' |
7 | import { Emailer } from '../../../lib/emailer' | 7 | import { Emailer } from '../../../lib/emailer' |
8 | import { Redis } from '../../../lib/redis' | 8 | import { Redis } from '../../../lib/redis' |
9 | import { createUserAccountAndChannelAndPlaylist } from '../../../lib/user' | 9 | import { createUserAccountAndChannelAndPlaylist, sendVerifyUserEmail } from '../../../lib/user' |
10 | import { | 10 | import { |
11 | asyncMiddleware, | 11 | asyncMiddleware, |
12 | asyncRetryTransactionMiddleware, | 12 | asyncRetryTransactionMiddleware, |
@@ -46,14 +46,18 @@ import { mySubscriptionsRouter } from './my-subscriptions' | |||
46 | import { CONFIG } from '../../../initializers/config' | 46 | import { CONFIG } from '../../../initializers/config' |
47 | import { sequelizeTypescript } from '../../../initializers/database' | 47 | import { sequelizeTypescript } from '../../../initializers/database' |
48 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' | 48 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' |
49 | import { UserRegister } from '../../../../shared/models/users/user-register.model' | ||
49 | 50 | ||
50 | const auditLogger = auditLoggerFactory('users') | 51 | const auditLogger = auditLoggerFactory('users') |
51 | 52 | ||
52 | const loginRateLimiter = new RateLimit({ | 53 | // FIXME: https://github.com/nfriedly/express-rate-limit/issues/138 |
54 | // @ts-ignore | ||
55 | const 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 | ||
57 | const askSendEmailLimiter = new RateLimit({ | 61 | const 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 |
@@ -143,7 +147,7 @@ usersRouter.post('/:id/reset-password', | |||
143 | usersRouter.post('/ask-send-verify-email', | 147 | usersRouter.post('/ask-send-verify-email', |
144 | askSendEmailLimiter, | 148 | askSendEmailLimiter, |
145 | asyncMiddleware(usersAskSendVerifyEmailValidator), | 149 | asyncMiddleware(usersAskSendVerifyEmailValidator), |
146 | asyncMiddleware(askSendVerifyUserEmail) | 150 | asyncMiddleware(reSendVerifyUserEmail) |
147 | ) | 151 | ) |
148 | 152 | ||
149 | usersRouter.post('/:id/verify-email', | 153 | usersRouter.post('/:id/verify-email', |
@@ -180,7 +184,7 @@ async function createUser (req: express.Request, res: express.Response) { | |||
180 | adminFlags: body.adminFlags || UserAdminFlag.NONE | 184 | adminFlags: body.adminFlags || UserAdminFlag.NONE |
181 | }) | 185 | }) |
182 | 186 | ||
183 | const { user, account } = await createUserAccountAndChannelAndPlaylist(userToCreate) | 187 | const { user, account } = await createUserAccountAndChannelAndPlaylist({ userToCreate: userToCreate }) |
184 | 188 | ||
185 | auditLogger.create(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON())) | 189 | auditLogger.create(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON())) |
186 | logger.info('User %s with its channel and account created.', body.username) | 190 | logger.info('User %s with its channel and account created.', body.username) |
@@ -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 | ||
199 | async function registerUser (req: express.Request, res: express.Response) { | 202 | async 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,11 @@ 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({ |
218 | userToCreate: userToCreate, | ||
219 | userDisplayName: body.displayName || undefined, | ||
220 | channelNames: body.channel | ||
221 | }) | ||
215 | 222 | ||
216 | auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON())) | 223 | auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON())) |
217 | logger.info('User %s with its channel and account registered.', body.username) | 224 | logger.info('User %s with its channel and account registered.', body.username) |
@@ -313,14 +320,7 @@ async function resetUserPassword (req: express.Request, res: express.Response) { | |||
313 | return res.status(204).end() | 320 | return res.status(204).end() |
314 | } | 321 | } |
315 | 322 | ||
316 | async function sendVerifyUserEmail (user: UserModel) { | 323 | async function reSendVerifyUserEmail (req: express.Request, res: express.Response) { |
317 | const verificationString = await Redis.Instance.setVerifyEmailVerificationString(user.id) | ||
318 | const url = WEBSERVER.URL + '/verify-account/email?userId=' + user.id + '&verificationString=' + verificationString | ||
319 | await Emailer.Instance.addVerifyEmailJob(user.email, url) | ||
320 | return | ||
321 | } | ||
322 | |||
323 | async function askSendVerifyUserEmail (req: express.Request, res: express.Response) { | ||
324 | const user = res.locals.user | 324 | const user = res.locals.user |
325 | 325 | ||
326 | await sendVerifyUserEmail(user) | 326 | await sendVerifyUserEmail(user) |
@@ -332,6 +332,11 @@ async function verifyUserEmail (req: express.Request, res: express.Response) { | |||
332 | const user = res.locals.user | 332 | const user = res.locals.user |
333 | user.emailVerified = true | 333 | user.emailVerified = true |
334 | 334 | ||
335 | if (req.body.isPendingEmail === true) { | ||
336 | user.email = user.pendingEmail | ||
337 | user.pendingEmail = null | ||
338 | } | ||
339 | |||
335 | await user.save() | 340 | await user.save() |
336 | 341 | ||
337 | return res.status(204).end() | 342 | return res.status(204).end() |
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index ddb239e7b..1750a02e9 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts | |||
@@ -28,6 +28,7 @@ import { VideoImportModel } from '../../../models/video/video-import' | |||
28 | import { AccountModel } from '../../../models/account/account' | 28 | import { AccountModel } from '../../../models/account/account' |
29 | import { CONFIG } from '../../../initializers/config' | 29 | import { CONFIG } from '../../../initializers/config' |
30 | import { sequelizeTypescript } from '../../../initializers/database' | 30 | import { sequelizeTypescript } from '../../../initializers/database' |
31 | import { sendVerifyUserEmail } from '../../../lib/user' | ||
31 | 32 | ||
32 | const auditLogger = auditLoggerFactory('users-me') | 33 | const auditLogger = auditLoggerFactory('users-me') |
33 | 34 | ||
@@ -171,17 +172,26 @@ async function deleteMe (req: express.Request, res: express.Response) { | |||
171 | 172 | ||
172 | async function updateMe (req: express.Request, res: express.Response) { | 173 | async function updateMe (req: express.Request, res: express.Response) { |
173 | const body: UserUpdateMe = req.body | 174 | const body: UserUpdateMe = req.body |
175 | let sendVerificationEmail = false | ||
174 | 176 | ||
175 | const user = res.locals.oauth.token.user | 177 | const user = res.locals.oauth.token.user |
176 | const oldUserAuditView = new UserAuditView(user.toFormattedJSON({})) | 178 | const oldUserAuditView = new UserAuditView(user.toFormattedJSON({})) |
177 | 179 | ||
178 | if (body.password !== undefined) user.password = body.password | 180 | if (body.password !== undefined) user.password = body.password |
179 | if (body.email !== undefined) user.email = body.email | ||
180 | if (body.nsfwPolicy !== undefined) user.nsfwPolicy = body.nsfwPolicy | 181 | if (body.nsfwPolicy !== undefined) user.nsfwPolicy = body.nsfwPolicy |
181 | if (body.webTorrentEnabled !== undefined) user.webTorrentEnabled = body.webTorrentEnabled | 182 | if (body.webTorrentEnabled !== undefined) user.webTorrentEnabled = body.webTorrentEnabled |
182 | if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo | 183 | if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo |
183 | if (body.videosHistoryEnabled !== undefined) user.videosHistoryEnabled = body.videosHistoryEnabled | 184 | if (body.videosHistoryEnabled !== undefined) user.videosHistoryEnabled = body.videosHistoryEnabled |
184 | 185 | ||
186 | if (body.email !== undefined) { | ||
187 | if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) { | ||
188 | user.pendingEmail = body.email | ||
189 | sendVerificationEmail = true | ||
190 | } else { | ||
191 | user.email = body.email | ||
192 | } | ||
193 | } | ||
194 | |||
185 | await sequelizeTypescript.transaction(async t => { | 195 | await sequelizeTypescript.transaction(async t => { |
186 | const userAccount = await AccountModel.load(user.Account.id) | 196 | const userAccount = await AccountModel.load(user.Account.id) |
187 | 197 | ||
@@ -196,6 +206,10 @@ async function updateMe (req: express.Request, res: express.Response) { | |||
196 | auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON({})), oldUserAuditView) | 206 | auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON({})), oldUserAuditView) |
197 | }) | 207 | }) |
198 | 208 | ||
209 | if (sendVerificationEmail === true) { | ||
210 | await sendVerifyUserEmail(user, true) | ||
211 | } | ||
212 | |||
199 | return res.sendStatus(204) | 213 | return res.sendStatus(204) |
200 | } | 214 | } |
201 | 215 | ||
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' | |||
19 | import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators' | 19 | import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators' |
20 | import { sendUpdateActor } from '../../lib/activitypub/send' | 20 | import { sendUpdateActor } from '../../lib/activitypub/send' |
21 | import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' | 21 | import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared' |
22 | import { createVideoChannel } from '../../lib/video-channel' | 22 | import { createVideoChannel, federateAllVideosOfChannel } from '../../lib/video-channel' |
23 | import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' | 23 | import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' |
24 | import { setAsyncActorKeys } from '../../lib/activitypub' | 24 | import { setAsyncActorKeys } from '../../lib/activitypub' |
25 | import { AccountModel } from '../../models/account/account' | 25 | import { 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 | ||
199 | async function removeVideoChannel (req: express.Request, res: express.Response) { | 214 | async 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' | |||
6 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' | 6 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' |
7 | import { getFormattedObjects, getServerActor } from '../../../helpers/utils' | 7 | import { getFormattedObjects, getServerActor } from '../../../helpers/utils' |
8 | import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist' | 8 | import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist' |
9 | import { MIMETYPES, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../initializers/constants' | 9 | import { |
10 | DEFAULT_AUDIO_RESOLUTION, | ||
11 | MIMETYPES, | ||
12 | VIDEO_CATEGORIES, | ||
13 | VIDEO_LANGUAGES, | ||
14 | VIDEO_LICENCES, | ||
15 | VIDEO_PRIVACIES | ||
16 | } from '../../../initializers/constants' | ||
10 | import { | 17 | import { |
11 | changeVideoChannelShare, | 18 | changeVideoChannelShare, |
12 | federateVideoIfNeeded, | 19 | federateVideoIfNeeded, |
@@ -54,6 +61,7 @@ import { CONFIG } from '../../../initializers/config' | |||
54 | import { sequelizeTypescript } from '../../../initializers/database' | 61 | import { sequelizeTypescript } from '../../../initializers/database' |
55 | import { createVideoMiniatureFromExisting, generateVideoMiniature } from '../../../lib/thumbnail' | 62 | import { createVideoMiniatureFromExisting, generateVideoMiniature } from '../../../lib/thumbnail' |
56 | import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' | 63 | import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' |
64 | import { VideoTranscodingPayload } from '../../../lib/job-queue/handlers/video-transcoding' | ||
57 | 65 | ||
58 | const auditLogger = auditLoggerFactory('videos') | 66 | const auditLogger = auditLoggerFactory('videos') |
59 | const videosRouter = express.Router() | 67 | const 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 | ||
197 | async function generateNodeinfo (req: express.Request, res: express.Response, next: express.NextFunction) { | 197 | async 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/core-utils.ts b/server/helpers/core-utils.ts index 305d3b71e..b1e9af0a1 100644 --- a/server/helpers/core-utils.ts +++ b/server/helpers/core-utils.ts | |||
@@ -134,6 +134,10 @@ function isProdInstance () { | |||
134 | return process.env.NODE_ENV === 'production' | 134 | return process.env.NODE_ENV === 'production' |
135 | } | 135 | } |
136 | 136 | ||
137 | function getAppNumber () { | ||
138 | return process.env.NODE_APP_INSTANCE | ||
139 | } | ||
140 | |||
137 | function root () { | 141 | function root () { |
138 | // We are in /helpers/utils.js | 142 | // We are in /helpers/utils.js |
139 | const paths = [ __dirname, '..', '..' ] | 143 | const paths = [ __dirname, '..', '..' ] |
@@ -256,6 +260,7 @@ const execPromise = promisify1<string, string>(exec) | |||
256 | export { | 260 | export { |
257 | isTestInstance, | 261 | isTestInstance, |
258 | isProdInstance, | 262 | isProdInstance, |
263 | getAppNumber, | ||
259 | 264 | ||
260 | objectConverter, | 265 | objectConverter, |
261 | root, | 266 | root, |
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 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { Response } from 'express' | 2 | import { Response } from 'express' |
3 | import 'express-validator' | 3 | import 'express-validator' |
4 | import * as validator from 'validator' | ||
5 | import { AccountModel } from '../../models/account/account' | 4 | import { AccountModel } from '../../models/account/account' |
6 | import { isUserDescriptionValid, isUserUsernameValid } from './users' | 5 | import { isUserDescriptionValid, isUserUsernameValid } from './users' |
7 | import { exists } from './misc' | 6 | import { exists } from './misc' |
@@ -18,14 +17,8 @@ function isAccountDescriptionValid (value: string) { | |||
18 | return isUserDescriptionValid(value) | 17 | return isUserDescriptionValid(value) |
19 | } | 18 | } |
20 | 19 | ||
21 | function doesAccountIdExist (id: number | string, res: Response, sendNotFound = true) { | 20 | function 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 | ||
29 | async function doesVideoChannelIdExist (id: number | string, res: express.Response) { | 29 | async 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 @@ | |||
1 | import * as ffmpeg from 'fluent-ffmpeg' | 1 | import * as ffmpeg from 'fluent-ffmpeg' |
2 | import { dirname, join } from 'path' | 2 | import { dirname, join } from 'path' |
3 | import { getTargetBitrate, VideoResolution } from '../../shared/models/videos' | 3 | import { getTargetBitrate, getMaxBitrate, VideoResolution } from '../../shared/models/videos' |
4 | import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants' | 4 | import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants' |
5 | import { processImage } from './image-utils' | 5 | import { processImage } from './image-utils' |
6 | import { logger } from './logger' | 6 | import { 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 | ||
33 | async function getVideoFileSize (path: string) { | 34 | async 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 | ||
51 | async function getVideoFileFPS (path: string) { | 52 | async 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 | ||
120 | type TranscodeOptions = { | 121 | type TranscodeOptionsType = 'hls' | 'quick-transcode' | 'video' | 'merge-audio' |
122 | |||
123 | interface 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?: { | 131 | interface HLSTranscodeOptions extends BaseTranscodeOptions { |
132 | type: 'hls' | ||
133 | hlsPlaylist: { | ||
127 | videoFilename: string | 134 | videoFilename: string |
128 | } | 135 | } |
129 | } | 136 | } |
130 | 137 | ||
138 | interface QuickTranscodeOptions extends BaseTranscodeOptions { | ||
139 | type: 'quick-transcode' | ||
140 | } | ||
141 | |||
142 | interface VideoTranscodeOptions extends BaseTranscodeOptions { | ||
143 | type: 'video' | ||
144 | } | ||
145 | |||
146 | interface MergeAudioTranscodeOptions extends BaseTranscodeOptions { | ||
147 | type: 'merge-audio' | ||
148 | audioPath: string | ||
149 | } | ||
150 | |||
151 | type TranscodeOptions = HLSTranscodeOptions | VideoTranscodeOptions | MergeAudioTranscodeOptions | QuickTranscodeOptions | ||
152 | |||
131 | function transcode (options: TranscodeOptions) { | 153 | function 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 | ||
191 | async 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 | ||
167 | export { | 217 | export { |
@@ -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 | ||
181 | async function buildx264Command (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { | 234 | async 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 | ||
211 | async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { | 264 | async 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 | |||
277 | async 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 | |||
286 | async 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 | ||
227 | function getHLSVideoPath (options: TranscodeOptions) { | 302 | function getHLSVideoPath (options: HLSTranscodeOptions) { |
228 | return `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}` | 303 | return `${dirname(options.outputPath)}/${options.hlsPlaylist.videoFilename}` |
229 | } | 304 | } |
230 | 305 | ||
231 | async function onTranscodingSuccess (options: TranscodeOptions) { | 306 | async 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 | ||
246 | function getVideoFileStream (path: string) { | 321 | function 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 | */ |
266 | async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, resolution: VideoResolution, fps: number): Promise<ffmpeg.FfmpegCommand> { | 341 | async 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 | */ | ||
288 | async 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 | */ |
302 | namespace audio { | 360 | namespace 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 | */ |
371 | async function presetH264 (command: ffmpeg.FfmpegCommand, resolution: VideoResolution, fps: number): Promise<ffmpeg.FfmpegCommand> { | 425 | async 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/helpers/logger.ts b/server/helpers/logger.ts index 734523b01..8603dd761 100644 --- a/server/helpers/logger.ts +++ b/server/helpers/logger.ts | |||
@@ -2,6 +2,7 @@ | |||
2 | import { mkdirpSync } from 'fs-extra' | 2 | import { mkdirpSync } from 'fs-extra' |
3 | import * as path from 'path' | 3 | import * as path from 'path' |
4 | import * as winston from 'winston' | 4 | import * as winston from 'winston' |
5 | import { FileTransportOptions } from 'winston/lib/winston/transports' | ||
5 | import { CONFIG } from '../initializers/config' | 6 | import { CONFIG } from '../initializers/config' |
6 | import { omit } from 'lodash' | 7 | import { omit } from 'lodash' |
7 | 8 | ||
@@ -45,6 +46,21 @@ const labelFormatter = winston.format.label({ | |||
45 | label | 46 | label |
46 | }) | 47 | }) |
47 | 48 | ||
49 | const fileLoggerOptions: FileTransportOptions = { | ||
50 | |||
51 | filename: path.join(CONFIG.STORAGE.LOG_DIR, 'peertube.log'), | ||
52 | handleExceptions: true, | ||
53 | format: winston.format.combine( | ||
54 | winston.format.timestamp(), | ||
55 | jsonLoggerFormat | ||
56 | ) | ||
57 | } | ||
58 | |||
59 | if (CONFIG.LOG.ROTATION) { | ||
60 | fileLoggerOptions.maxsize = 1024 * 1024 * 12 | ||
61 | fileLoggerOptions.maxFiles = 20 | ||
62 | } | ||
63 | |||
48 | const logger = winston.createLogger({ | 64 | const logger = winston.createLogger({ |
49 | level: CONFIG.LOG.LEVEL, | 65 | level: CONFIG.LOG.LEVEL, |
50 | format: winston.format.combine( | 66 | format: winston.format.combine( |
@@ -52,16 +68,7 @@ const logger = winston.createLogger({ | |||
52 | winston.format.splat() | 68 | winston.format.splat() |
53 | ), | 69 | ), |
54 | transports: [ | 70 | transports: [ |
55 | new winston.transports.File({ | 71 | new winston.transports.File(fileLoggerOptions), |
56 | filename: path.join(CONFIG.STORAGE.LOG_DIR, 'peertube.log'), | ||
57 | handleExceptions: true, | ||
58 | maxsize: 1024 * 1024 * 12, | ||
59 | maxFiles: 20, | ||
60 | format: winston.format.combine( | ||
61 | winston.format.timestamp(), | ||
62 | jsonLoggerFormat | ||
63 | ) | ||
64 | }), | ||
65 | new winston.transports.Console({ | 72 | new winston.transports.Console({ |
66 | handleExceptions: true, | 73 | handleExceptions: true, |
67 | format: winston.format.combine( | 74 | format: winston.format.combine( |
diff --git a/server/initializers/checker-before-init.ts b/server/initializers/checker-before-init.ts index 622ad7d6b..c211d725c 100644 --- a/server/initializers/checker-before-init.ts +++ b/server/initializers/checker-before-init.ts | |||
@@ -10,6 +10,7 @@ function checkMissedConfig () { | |||
10 | 'trust_proxy', | 10 | 'trust_proxy', |
11 | 'database.hostname', 'database.port', 'database.suffix', 'database.username', 'database.password', 'database.pool.max', | 11 | 'database.hostname', 'database.port', 'database.suffix', 'database.username', 'database.password', 'database.pool.max', |
12 | 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address', | 12 | 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address', |
13 | 'email.body.signature', 'email.object.prefix', | ||
13 | 'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache', | 14 | 'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache', |
14 | 'storage.redundancy', 'storage.tmp', 'storage.streaming_playlists', | 15 | 'storage.redundancy', 'storage.tmp', 'storage.streaming_playlists', |
15 | 'log.level', | 16 | 'log.level', |
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index 4f77e144d..bb278ba43 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')), |
@@ -75,7 +83,8 @@ const CONFIG = { | |||
75 | }, | 83 | }, |
76 | TRUST_PROXY: config.get<string[]>('trust_proxy'), | 84 | TRUST_PROXY: config.get<string[]>('trust_proxy'), |
77 | LOG: { | 85 | LOG: { |
78 | LEVEL: config.get<string>('log.level') | 86 | LEVEL: config.get<string>('log.level'), |
87 | ROTATION: config.get<boolean>('log.rotation.enabled') | ||
79 | }, | 88 | }, |
80 | SEARCH: { | 89 | SEARCH: { |
81 | REMOTE_URI: { | 90 | REMOTE_URI: { |
@@ -140,13 +149,15 @@ const CONFIG = { | |||
140 | TRANSCODING: { | 149 | TRANSCODING: { |
141 | get ENABLED () { return config.get<boolean>('transcoding.enabled') }, | 150 | get ENABLED () { return config.get<boolean>('transcoding.enabled') }, |
142 | get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') }, | 151 | get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') }, |
152 | get ALLOW_AUDIO_FILES () { return config.get<boolean>('transcoding.allow_audio_files') }, | ||
143 | get THREADS () { return config.get<number>('transcoding.threads') }, | 153 | get THREADS () { return config.get<number>('transcoding.threads') }, |
144 | RESOLUTIONS: { | 154 | RESOLUTIONS: { |
145 | get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') }, | 155 | get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') }, |
146 | get '360p' () { return config.get<boolean>('transcoding.resolutions.360p') }, | 156 | get '360p' () { return config.get<boolean>('transcoding.resolutions.360p') }, |
147 | get '480p' () { return config.get<boolean>('transcoding.resolutions.480p') }, | 157 | get '480p' () { return config.get<boolean>('transcoding.resolutions.480p') }, |
148 | get '720p' () { return config.get<boolean>('transcoding.resolutions.720p') }, | 158 | get '720p' () { return config.get<boolean>('transcoding.resolutions.720p') }, |
149 | get '1080p' () { return config.get<boolean>('transcoding.resolutions.1080p') } | 159 | get '1080p' () { return config.get<boolean>('transcoding.resolutions.1080p') }, |
160 | get '2160p' () { return config.get<boolean>('transcoding.resolutions.2160p') } | ||
150 | }, | 161 | }, |
151 | HLS: { | 162 | HLS: { |
152 | get ENABLED () { return config.get<boolean>('transcoding.hls.enabled') } | 163 | get ENABLED () { return config.get<boolean>('transcoding.hls.enabled') } |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index b5f8fc0bc..c2b8eff95 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import { join } from 'path' | 1 | import { join } from 'path' |
2 | import { JobType, VideoRateType, VideoState } from '../../shared/models' | 2 | import { JobType, VideoRateType, VideoResolution, VideoState } from '../../shared/models' |
3 | import { ActivityPubActorType } from '../../shared/models/activitypub' | 3 | import { ActivityPubActorType } from '../../shared/models/activitypub' |
4 | import { FollowState } from '../../shared/models/actors' | 4 | import { FollowState } from '../../shared/models/actors' |
5 | import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos' | 5 | import { 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 |
7 | import { isTestInstance, sanitizeHost, sanitizeUrl } from '../helpers/core-utils' | 7 | import { isTestInstance, sanitizeHost, sanitizeUrl, root } from '../helpers/core-utils' |
8 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' | 8 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' |
9 | import { invert } from 'lodash' | 9 | import { invert } from 'lodash' |
10 | import { CronRepeatOptions, EveryRepeatOptions } from 'bull' | 10 | import { CronRepeatOptions, EveryRepeatOptions } from 'bull' |
@@ -14,7 +14,7 @@ import { CONFIG, registerConfigChangedHandler } from './config' | |||
14 | 14 | ||
15 | // --------------------------------------------------------------------------- | 15 | // --------------------------------------------------------------------------- |
16 | 16 | ||
17 | const LAST_MIGRATION_VERSION = 380 | 17 | const LAST_MIGRATION_VERSION = 390 |
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 | ||
303 | const DEFAULT_AUDIO_RESOLUTION = VideoResolution.H_480P | ||
304 | |||
303 | const VIDEO_RATE_TYPES: { [ id: string ]: VideoRateType } = { | 305 | const 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 | ||
382 | const MIMETYPES = { | 384 | const 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 | } |
406 | MIMETYPES.VIDEO.EXT_MIMETYPE = invert(MIMETYPES.VIDEO.MIMETYPE_EXT) | 418 | MIMETYPES.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 | } |
499 | const PREVIEWS_SIZE = { | 511 | const PREVIEWS_SIZE = { |
500 | width: 560, | 512 | width: 850, |
501 | height: 315 | 513 | height: 480 |
502 | } | 514 | } |
503 | const AVATARS_SIZE = { | 515 | const AVATARS_SIZE = { |
504 | width: 120, | 516 | width: 120, |
@@ -543,6 +555,10 @@ const REDUNDANCY = { | |||
543 | 555 | ||
544 | const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS) | 556 | const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS) |
545 | 557 | ||
558 | const ASSETS_PATH = { | ||
559 | DEFAULT_AUDIO_BACKGROUND: join(root(), 'server', 'assets', 'default-audio-background.jpg') | ||
560 | } | ||
561 | |||
546 | // --------------------------------------------------------------------------- | 562 | // --------------------------------------------------------------------------- |
547 | 563 | ||
548 | const CUSTOM_HTML_TAG_COMMENTS = { | 564 | const CUSTOM_HTML_TAG_COMMENTS = { |
@@ -612,6 +628,7 @@ if (isTestInstance() === true) { | |||
612 | } | 628 | } |
613 | 629 | ||
614 | updateWebserverUrls() | 630 | updateWebserverUrls() |
631 | updateWebserverConfig() | ||
615 | 632 | ||
616 | registerConfigChangedHandler(() => { | 633 | registerConfigChangedHandler(() => { |
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 | ||
726 | function updateWebserverConfig () { | 751 | function 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 | ||
733 | function buildVideosExtname () { | 759 | function 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 | ||
739 | function loadLanguages () { | 763 | function loadLanguages () { |
diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts index 127449577..cb58454cb 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({ userToCreate: user, channelNames: undefined, validateUser: 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/0100-activitypub.ts b/server/initializers/migrations/0100-activitypub.ts index 2880a97d9..96d44a7ce 100644 --- a/server/initializers/migrations/0100-activitypub.ts +++ b/server/initializers/migrations/0100-activitypub.ts | |||
@@ -65,7 +65,12 @@ async function up (utils: { | |||
65 | // Create application account | 65 | // Create application account |
66 | { | 66 | { |
67 | const applicationInstance = await ApplicationModel.findOne() | 67 | const applicationInstance = await ApplicationModel.findOne() |
68 | const accountCreated = await createLocalAccountWithoutKeys(SERVER_ACTOR_NAME, null, applicationInstance.id, undefined) | 68 | const accountCreated = await createLocalAccountWithoutKeys({ |
69 | name: SERVER_ACTOR_NAME, | ||
70 | userId: null, | ||
71 | applicationId: applicationInstance.id, | ||
72 | t: undefined | ||
73 | }) | ||
69 | 74 | ||
70 | const { publicKey, privateKey } = await createPrivateAndPublicKeys() | 75 | const { publicKey, privateKey } = await createPrivateAndPublicKeys() |
71 | accountCreated.Actor.publicKey = publicKey | 76 | accountCreated.Actor.publicKey = publicKey |
@@ -83,7 +88,7 @@ async function up (utils: { | |||
83 | // Recreate accounts for each user | 88 | // Recreate accounts for each user |
84 | const users = await db.User.findAll() | 89 | const users = await db.User.findAll() |
85 | for (const user of users) { | 90 | for (const user of users) { |
86 | const account = await createLocalAccountWithoutKeys(user.username, user.id, null, undefined) | 91 | const account = await createLocalAccountWithoutKeys({ name: user.username, userId: user.id, applicationId: null, t: undefined }) |
87 | 92 | ||
88 | const { publicKey, privateKey } = await createPrivateAndPublicKeys() | 93 | const { publicKey, privateKey } = await createPrivateAndPublicKeys() |
89 | account.Actor.publicKey = publicKey | 94 | account.Actor.publicKey = publicKey |
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 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | async 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 | |||
12 | function down (options) { | ||
13 | throw new Error('Not implemented.') | ||
14 | } | ||
15 | |||
16 | export { | ||
17 | up, | ||
18 | down | ||
19 | } | ||
diff --git a/server/initializers/migrations/0390-user-pending-email.ts b/server/initializers/migrations/0390-user-pending-email.ts new file mode 100644 index 000000000..5ca871746 --- /dev/null +++ b/server/initializers/migrations/0390-user-pending-email.ts | |||
@@ -0,0 +1,25 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | async function up (utils: { | ||
4 | transaction: Sequelize.Transaction, | ||
5 | queryInterface: Sequelize.QueryInterface, | ||
6 | sequelize: Sequelize.Sequelize, | ||
7 | db: any | ||
8 | }): Promise<void> { | ||
9 | const data = { | ||
10 | type: Sequelize.STRING(400), | ||
11 | allowNull: true, | ||
12 | defaultValue: null | ||
13 | } | ||
14 | |||
15 | await utils.queryInterface.addColumn('user', 'pendingEmail', data) | ||
16 | } | ||
17 | |||
18 | function down (options) { | ||
19 | throw new Error('Not implemented.') | ||
20 | } | ||
21 | |||
22 | export { | ||
23 | up, | ||
24 | down | ||
25 | } | ||
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' | |||
5 | import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' | 5 | import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' |
6 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' | 6 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' |
7 | import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' | 7 | import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' |
8 | import { isActorObjectValid, normalizeActor } from '../../helpers/custom-validators/activitypub/actor' | 8 | import { sanitizeAndCheckActorObject } from '../../helpers/custom-validators/activitypub/actor' |
9 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 9 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
10 | import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' | 10 | import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' |
11 | import { logger } from '../../helpers/logger' | 11 | import { 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 | ||
145 | async function updateActorAvatarInstance (actorInstance: ActorModel, avatarName: string, t: Transaction) { | 144 | async 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' | |||
5 | import { VideoShareModel } from '../../../models/video/video-share' | 5 | import { VideoShareModel } from '../../../models/video/video-share' |
6 | import { forwardVideoRelatedActivity } from '../send/utils' | 6 | import { forwardVideoRelatedActivity } from '../send/utils' |
7 | import { getOrCreateVideoAndAccountAndChannel } from '../videos' | 7 | import { getOrCreateVideoAndAccountAndChannel } from '../videos' |
8 | import { VideoPrivacy } from '../../../../shared/models/videos' | ||
9 | import { Notifier } from '../../notifier' | 8 | import { Notifier } from '../../notifier' |
9 | import { VideoModel } from '../../../models/video/video' | ||
10 | import { logger } from '../../../helpers/logger' | ||
10 | 11 | ||
11 | async function processAnnounceActivity (activity: ActivityAnnounce, actorAnnouncer: ActorModel) { | 12 | async function processAnnounceActivity (activity: ActivityAnnounce, actorAnnouncer: ActorModel) { |
12 | return retryTransactionWrapper(processVideoShare, actorAnnouncer, activity) | 13 | return retryTransactionWrapper(processVideoShare, actorAnnouncer, activity) |
@@ -23,7 +24,17 @@ export { | |||
23 | async function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnounce) { | 24 | async 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' | |||
9 | import { forwardVideoRelatedActivity } from '../send/utils' | 9 | import { forwardVideoRelatedActivity } from '../send/utils' |
10 | import { createOrUpdateCacheFile } from '../cache-file' | 10 | import { createOrUpdateCacheFile } from '../cache-file' |
11 | import { Notifier } from '../../notifier' | 11 | import { Notifier } from '../../notifier' |
12 | import { processViewActivity } from './process-view' | ||
13 | import { processDislikeActivity } from './process-dislike' | ||
14 | import { processFlagActivity } from './process-flag' | ||
15 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' | 12 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' |
16 | import { createOrUpdateVideoPlaylist } from '../playlist' | 13 | import { createOrUpdateVideoPlaylist } from '../playlist' |
14 | import { VideoModel } from '../../../models/video/video' | ||
17 | 15 | ||
18 | async function processCreateActivity (activity: ActivityCreate, byActor: ActorModel) { | 16 | async 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 | ||
97 | async function processDeleteAccount (accountToRemove: AccountModel) { | 97 | async 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 | ||
107 | async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelModel) { | 107 | async 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 | ||
117 | function processDeleteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) { | 117 | function 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 | |||
95 | async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) { | 95 | async 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 | ||
83 | async function resolveThread (url: string, comments: VideoCommentModel[] = []) { | 83 | type ResolveThreadResult = Promise<{ video: VideoModel, parents: VideoCommentModel[] }> |
84 | async 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 | ||
167 | export { | 167 | export { |
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 @@ | |||
1 | import * as Bull from 'bull' | 1 | import * as Bull from 'bull' |
2 | import { logger } from '../../../helpers/logger' | 2 | import { logger } from '../../../helpers/logger' |
3 | import { VideoModel } from '../../../models/video/video' | 3 | import { VideoModel } from '../../../models/video/video' |
4 | import { publishVideoIfNeeded } from './video-transcoding' | 4 | import { publishNewResolutionIfNeeded } from './video-transcoding' |
5 | import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' | 5 | import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' |
6 | import { copy, stat } from 'fs-extra' | 6 | import { copy, stat } from 'fs-extra' |
7 | import { VideoFileModel } from '../../../models/video/video-file' | 7 | import { 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' | |||
8 | import { sequelizeTypescript } from '../../../initializers' | 8 | import { sequelizeTypescript } from '../../../initializers' |
9 | import * as Bluebird from 'bluebird' | 9 | import * as Bluebird from 'bluebird' |
10 | import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' | 10 | import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' |
11 | import { generateHlsPlaylist, optimizeVideofile, transcodeOriginalVideofile } from '../../video-transcoding' | 11 | import { generateHlsPlaylist, optimizeVideofile, transcodeOriginalVideofile, mergeAudioVideofile } from '../../video-transcoding' |
12 | import { Notifier } from '../../notifier' | 12 | import { Notifier } from '../../notifier' |
13 | import { CONFIG } from '../../../initializers/config' | 13 | import { CONFIG } from '../../../initializers/config' |
14 | 14 | ||
15 | export type VideoTranscodingPayload = { | 15 | interface BaseTranscodingPayload { |
16 | videoUUID: string | 16 | videoUUID: string |
17 | resolution?: VideoResolution | ||
18 | isNewVideo?: boolean | 17 | isNewVideo?: boolean |
18 | } | ||
19 | |||
20 | interface HLSTranscodingPayload extends BaseTranscodingPayload { | ||
21 | type: 'hls' | ||
22 | isPortraitMode?: boolean | ||
23 | resolution: VideoResolution | ||
24 | } | ||
25 | |||
26 | interface NewResolutionTranscodingPayload extends BaseTranscodingPayload { | ||
27 | type: 'new-resolution' | ||
19 | isPortraitMode?: boolean | 28 | isPortraitMode?: boolean |
20 | generateHlsPlaylist?: boolean | 29 | resolution: VideoResolution |
30 | } | ||
31 | |||
32 | interface MergeAudioTranscodingPayload extends BaseTranscodingPayload { | ||
33 | type: 'merge-audio' | ||
34 | resolution: VideoResolution | ||
35 | } | ||
36 | |||
37 | interface OptimizeTranscodingPayload extends BaseTranscodingPayload { | ||
38 | type: 'optimize' | ||
21 | } | 39 | } |
22 | 40 | ||
41 | export type VideoTranscodingPayload = HLSTranscodingPayload | NewResolutionTranscodingPayload | ||
42 | | OptimizeTranscodingPayload | MergeAudioTranscodingPayload | ||
43 | |||
23 | async function processVideoTranscoding (job: Bull.Job) { | 44 | async 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 | ||
65 | async function publishVideoIfNeeded (video: VideoModel, payload?: VideoTranscodingPayload) { | 90 | async 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 | ||
97 | async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: VideoTranscodingPayload) { | 122 | async 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 | ||
157 | export { | 184 | export { |
158 | processVideoTranscoding, | 185 | processVideoTranscoding, |
159 | publishVideoIfNeeded | 186 | publishNewResolutionIfNeeded |
160 | } | 187 | } |
161 | 188 | ||
162 | // --------------------------------------------------------------------------- | 189 | // --------------------------------------------------------------------------- |
163 | 190 | ||
164 | function createHlsJobIfEnabled (payload?: VideoTranscodingPayload) { | 191 | function 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 @@ | |||
1 | import { VideoFileModel } from '../models/video/video-file' | 1 | import { VideoFileModel } from '../models/video/video-file' |
2 | import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils' | 2 | import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils' |
3 | import { CONFIG } from '../initializers/config' | 3 | import { CONFIG } from '../initializers/config' |
4 | import { PREVIEWS_SIZE, THUMBNAILS_SIZE } from '../initializers/constants' | 4 | import { PREVIEWS_SIZE, THUMBNAILS_SIZE, ASSETS_PATH } from '../initializers/constants' |
5 | import { VideoModel } from '../models/video/video' | 5 | import { VideoModel } from '../models/video/video' |
6 | import { ThumbnailModel } from '../models/video/thumbnail' | 6 | import { ThumbnailModel } from '../models/video/thumbnail' |
7 | import { ThumbnailType } from '../../shared/models/videos/thumbnail.type' | 7 | import { ThumbnailType } from '../../shared/models/videos/thumbnail.type' |
@@ -45,8 +45,10 @@ function createVideoMiniatureFromExisting (inputPath: string, video: VideoModel, | |||
45 | function generateVideoMiniature (video: VideoModel, videoFile: VideoFileModel, type: ThumbnailType) { | 45 | function 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..0e4007770 100644 --- a/server/lib/user.ts +++ b/server/lib/user.ts | |||
@@ -1,7 +1,6 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | import * as uuidv4 from 'uuid/v4' | 1 | import * as uuidv4 from 'uuid/v4' |
3 | import { ActivityPubActorType } from '../../shared/models/activitypub' | 2 | import { ActivityPubActorType } from '../../shared/models/activitypub' |
4 | import { SERVER_ACTOR_NAME } from '../initializers/constants' | 3 | import { SERVER_ACTOR_NAME, WEBSERVER } from '../initializers/constants' |
5 | import { AccountModel } from '../models/account/account' | 4 | import { AccountModel } from '../models/account/account' |
6 | import { UserModel } from '../models/account/user' | 5 | import { UserModel } from '../models/account/user' |
7 | import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub' | 6 | import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub' |
@@ -12,8 +11,19 @@ import { UserNotificationSettingModel } from '../models/account/user-notificatio | |||
12 | import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users' | 11 | import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users' |
13 | import { createWatchLaterPlaylist } from './video-playlist' | 12 | import { createWatchLaterPlaylist } from './video-playlist' |
14 | import { sequelizeTypescript } from '../initializers/database' | 13 | import { sequelizeTypescript } from '../initializers/database' |
14 | import { Transaction } from 'sequelize/types' | ||
15 | import { Redis } from './redis' | ||
16 | import { Emailer } from './emailer' | ||
17 | |||
18 | type ChannelNames = { name: string, displayName: string } | ||
19 | async function createUserAccountAndChannelAndPlaylist (parameters: { | ||
20 | userToCreate: UserModel, | ||
21 | userDisplayName?: string, | ||
22 | channelNames?: ChannelNames, | ||
23 | validateUser?: boolean | ||
24 | }) { | ||
25 | const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters | ||
15 | 26 | ||
16 | async function createUserAccountAndChannelAndPlaylist (userToCreate: UserModel, validateUser = true) { | ||
17 | const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => { | 27 | const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => { |
18 | const userOptions = { | 28 | const userOptions = { |
19 | transaction: t, | 29 | transaction: t, |
@@ -23,21 +33,17 @@ async function createUserAccountAndChannelAndPlaylist (userToCreate: UserModel, | |||
23 | const userCreated = await userToCreate.save(userOptions) | 33 | const userCreated = await userToCreate.save(userOptions) |
24 | userCreated.NotificationSetting = await createDefaultUserNotificationSettings(userCreated, t) | 34 | userCreated.NotificationSetting = await createDefaultUserNotificationSettings(userCreated, t) |
25 | 35 | ||
26 | const accountCreated = await createLocalAccountWithoutKeys(userCreated.username, userCreated.id, null, t) | 36 | const accountCreated = await createLocalAccountWithoutKeys({ |
37 | name: userCreated.username, | ||
38 | displayName: userDisplayName, | ||
39 | userId: userCreated.id, | ||
40 | applicationId: null, | ||
41 | t: t | ||
42 | }) | ||
27 | userCreated.Account = accountCreated | 43 | userCreated.Account = accountCreated |
28 | 44 | ||
29 | let channelName = userCreated.username + '_channel' | 45 | const channelAttributes = await buildChannelAttributes(userCreated, channelNames) |
30 | 46 | 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 | 47 | ||
42 | const videoPlaylist = await createWatchLaterPlaylist(accountCreated, t) | 48 | const videoPlaylist = await createWatchLaterPlaylist(accountCreated, t) |
43 | 49 | ||
@@ -55,20 +61,22 @@ async function createUserAccountAndChannelAndPlaylist (userToCreate: UserModel, | |||
55 | return { user, account, videoChannel } as { user: UserModel, account: AccountModel, videoChannel: VideoChannelModel } | 61 | return { user, account, videoChannel } as { user: UserModel, account: AccountModel, videoChannel: VideoChannelModel } |
56 | } | 62 | } |
57 | 63 | ||
58 | async function createLocalAccountWithoutKeys ( | 64 | async function createLocalAccountWithoutKeys (parameters: { |
59 | name: string, | 65 | name: string, |
66 | displayName?: string, | ||
60 | userId: number | null, | 67 | userId: number | null, |
61 | applicationId: number | null, | 68 | applicationId: number | null, |
62 | t: Sequelize.Transaction | undefined, | 69 | t: Transaction | undefined, |
63 | type: ActivityPubActorType= 'Person' | 70 | type?: ActivityPubActorType |
64 | ) { | 71 | }) { |
72 | const { name, displayName, userId, applicationId, t, type = 'Person' } = parameters | ||
65 | const url = getAccountActivityPubUrl(name) | 73 | const url = getAccountActivityPubUrl(name) |
66 | 74 | ||
67 | const actorInstance = buildActorInstance(type, url, name) | 75 | const actorInstance = buildActorInstance(type, url, name) |
68 | const actorInstanceCreated = await actorInstance.save({ transaction: t }) | 76 | const actorInstanceCreated = await actorInstance.save({ transaction: t }) |
69 | 77 | ||
70 | const accountInstance = new AccountModel({ | 78 | const accountInstance = new AccountModel({ |
71 | name, | 79 | name: displayName || name, |
72 | userId, | 80 | userId, |
73 | applicationId, | 81 | applicationId, |
74 | actorId: actorInstanceCreated.id | 82 | actorId: actorInstanceCreated.id |
@@ -81,24 +89,42 @@ async function createLocalAccountWithoutKeys ( | |||
81 | } | 89 | } |
82 | 90 | ||
83 | async function createApplicationActor (applicationId: number) { | 91 | async function createApplicationActor (applicationId: number) { |
84 | const accountCreated = await createLocalAccountWithoutKeys(SERVER_ACTOR_NAME, null, applicationId, undefined, 'Application') | 92 | const accountCreated = await createLocalAccountWithoutKeys({ |
93 | name: SERVER_ACTOR_NAME, | ||
94 | userId: null, | ||
95 | applicationId: applicationId, | ||
96 | t: undefined, | ||
97 | type: 'Application' | ||
98 | }) | ||
85 | 99 | ||
86 | accountCreated.Actor = await setAsyncActorKeys(accountCreated.Actor) | 100 | accountCreated.Actor = await setAsyncActorKeys(accountCreated.Actor) |
87 | 101 | ||
88 | return accountCreated | 102 | return accountCreated |
89 | } | 103 | } |
90 | 104 | ||
105 | async function sendVerifyUserEmail (user: UserModel, isPendingEmail = false) { | ||
106 | const verificationString = await Redis.Instance.setVerifyEmailVerificationString(user.id) | ||
107 | let url = WEBSERVER.URL + '/verify-account/email?userId=' + user.id + '&verificationString=' + verificationString | ||
108 | |||
109 | if (isPendingEmail) url += '&isPendingEmail=true' | ||
110 | |||
111 | const email = isPendingEmail ? user.pendingEmail : user.email | ||
112 | |||
113 | await Emailer.Instance.addVerifyEmailJob(email, url) | ||
114 | } | ||
115 | |||
91 | // --------------------------------------------------------------------------- | 116 | // --------------------------------------------------------------------------- |
92 | 117 | ||
93 | export { | 118 | export { |
94 | createApplicationActor, | 119 | createApplicationActor, |
95 | createUserAccountAndChannelAndPlaylist, | 120 | createUserAccountAndChannelAndPlaylist, |
96 | createLocalAccountWithoutKeys | 121 | createLocalAccountWithoutKeys, |
122 | sendVerifyUserEmail | ||
97 | } | 123 | } |
98 | 124 | ||
99 | // --------------------------------------------------------------------------- | 125 | // --------------------------------------------------------------------------- |
100 | 126 | ||
101 | function createDefaultUserNotificationSettings (user: UserModel, t: Sequelize.Transaction | undefined) { | 127 | function createDefaultUserNotificationSettings (user: UserModel, t: Transaction | undefined) { |
102 | const values: UserNotificationSetting & { userId: number } = { | 128 | const values: UserNotificationSetting & { userId: number } = { |
103 | userId: user.id, | 129 | userId: user.id, |
104 | newVideoFromSubscription: UserNotificationSettingValue.WEB, | 130 | newVideoFromSubscription: UserNotificationSettingValue.WEB, |
@@ -116,3 +142,20 @@ function createDefaultUserNotificationSettings (user: UserModel, t: Sequelize.Tr | |||
116 | 142 | ||
117 | return UserNotificationSettingModel.create(values, { transaction: t }) | 143 | return UserNotificationSettingModel.create(values, { transaction: t }) |
118 | } | 144 | } |
145 | |||
146 | async function buildChannelAttributes (user: UserModel, channelNames?: ChannelNames) { | ||
147 | if (channelNames) return channelNames | ||
148 | |||
149 | let channelName = user.username + '_channel' | ||
150 | |||
151 | // Conflict, generate uuid instead | ||
152 | const actor = await ActorModel.loadLocalByName(channelName) | ||
153 | if (actor) channelName = uuidv4() | ||
154 | |||
155 | const videoChannelDisplayName = `Main ${user.username} channel` | ||
156 | |||
157 | return { | ||
158 | name: channelName, | ||
159 | displayName: videoChannelDisplayName | ||
160 | } | ||
161 | } | ||
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' | |||
3 | import { VideoChannelCreate } from '../../shared/models' | 3 | import { VideoChannelCreate } from '../../shared/models' |
4 | import { AccountModel } from '../models/account/account' | 4 | import { AccountModel } from '../models/account/account' |
5 | import { VideoChannelModel } from '../models/video/video-channel' | 5 | import { VideoChannelModel } from '../models/video/video-channel' |
6 | import { buildActorInstance, getVideoChannelActivityPubUrl } from './activitypub' | 6 | import { buildActorInstance, federateVideoIfNeeded, getVideoChannelActivityPubUrl } from './activitypub' |
7 | import { VideoModel } from '../models/video/video' | ||
7 | 8 | ||
8 | async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountModel, t: Sequelize.Transaction) { | 9 | async 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 | ||
37 | async 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 | ||
38 | export { | 49 | export { |
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 @@ | |||
1 | import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../initializers/constants' | 1 | import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../initializers/constants' |
2 | import { join } from 'path' | 2 | import { join } from 'path' |
3 | import { getVideoFileFPS, transcode } from '../helpers/ffmpeg-utils' | 3 | import { canDoQuickTranscode, getVideoFileFPS, transcode, TranscodeOptions, TranscodeOptionsType } from '../helpers/ffmpeg-utils' |
4 | import { ensureDir, move, remove, stat } from 'fs-extra' | 4 | import { ensureDir, move, remove, stat } from 'fs-extra' |
5 | import { logger } from '../helpers/logger' | 5 | import { logger } from '../helpers/logger' |
6 | import { VideoResolution } from '../../shared/models/videos' | 6 | import { VideoResolution } from '../../shared/models/videos' |
@@ -11,15 +11,24 @@ import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-pla | |||
11 | import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' | 11 | import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' |
12 | import { CONFIG } from '../initializers/config' | 12 | import { CONFIG } from '../initializers/config' |
13 | 13 | ||
14 | /** | ||
15 | * Optimize the original video file and replace it. The resolution is not changed. | ||
16 | */ | ||
14 | async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFileModel) { | 17 | async 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 | */ | ||
55 | async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoResolution, isPortrait: boolean) { | 60 | async 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 | |||
90 | async 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 | ||
92 | async function generateHlsPlaylist (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) { | 120 | async 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 | |||
128 | export { | 159 | export { |
129 | generateHlsPlaylist, | 160 | generateHlsPlaylist, |
130 | optimizeVideofile, | 161 | optimizeVideofile, |
131 | transcodeOriginalVideofile | 162 | transcodeOriginalVideofile, |
163 | mergeAudioVideofile | ||
164 | } | ||
165 | |||
166 | // --------------------------------------------------------------------------- | ||
167 | |||
168 | async 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 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { param, query } from 'express-validator/check' | 2 | import { param, query } from 'express-validator/check' |
3 | import { doesAccountIdExist, isAccountNameValid, doesAccountNameWithHostExist } from '../../helpers/custom-validators/accounts' | 3 | import { doesAccountIdExist, doesAccountNameWithHostExist } from '../../helpers/custom-validators/accounts' |
4 | import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' | 4 | import { isIdOrUUIDValid, isIdValid } from '../../helpers/custom-validators/misc' |
5 | import { logger } from '../../helpers/logger' | 5 | import { logger } from '../../helpers/logger' |
6 | import { areValidationErrors } from './utils' | 6 | import { areValidationErrors } from './utils' |
7 | import { isValidRSSFeed } from '../../helpers/custom-validators/feeds' | 7 | import { isValidRSSFeed } from '../../helpers/custom-validators/feeds' |
8 | import { doesVideoChannelIdExist, doesVideoChannelNameWithHostExist } from '../../helpers/custom-validators/video-channels' | 8 | import { doesVideoChannelIdExist, doesVideoChannelNameWithHostExist } from '../../helpers/custom-validators/video-channels' |
9 | import { doesVideoExist } from '../../helpers/custom-validators/videos' | 9 | import { doesVideoExist } from '../../helpers/custom-validators/videos' |
10 | import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor' | ||
11 | 10 | ||
12 | const videoFeedsValidator = [ | 11 | const 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..ec70fa0fd 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts | |||
@@ -25,6 +25,9 @@ import { Redis } from '../../lib/redis' | |||
25 | import { UserModel } from '../../models/account/user' | 25 | import { UserModel } from '../../models/account/user' |
26 | import { areValidationErrors } from './utils' | 26 | import { areValidationErrors } from './utils' |
27 | import { ActorModel } from '../../models/activitypub/actor' | 27 | import { ActorModel } from '../../models/activitypub/actor' |
28 | import { isActorPreferredUsernameValid } from '../../helpers/custom-validators/activitypub/actor' | ||
29 | import { isVideoChannelNameValid } from '../../helpers/custom-validators/video-channels' | ||
30 | import { UserRegister } from '../../../shared/models/users/user-register.model' | ||
28 | 31 | ||
29 | const usersAddValidator = [ | 32 | const usersAddValidator = [ |
30 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), | 33 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), |
@@ -49,6 +52,16 @@ const usersRegisterValidator = [ | |||
49 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username'), | 52 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username'), |
50 | body('password').custom(isUserPasswordValid).withMessage('Should have a valid password'), | 53 | body('password').custom(isUserPasswordValid).withMessage('Should have a valid password'), |
51 | body('email').isEmail().withMessage('Should have a valid email'), | 54 | body('email').isEmail().withMessage('Should have a valid email'), |
55 | body('displayName') | ||
56 | .optional() | ||
57 | .custom(isUserDisplayNameValid).withMessage('Should have a valid display name'), | ||
58 | |||
59 | body('channel.name') | ||
60 | .optional() | ||
61 | .custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'), | ||
62 | body('channel.displayName') | ||
63 | .optional() | ||
64 | .custom(isVideoChannelNameValid).withMessage('Should have a valid display name'), | ||
52 | 65 | ||
53 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 66 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
54 | logger.debug('Checking usersRegister parameters', { parameters: omit(req.body, 'password') }) | 67 | logger.debug('Checking usersRegister parameters', { parameters: omit(req.body, 'password') }) |
@@ -56,6 +69,28 @@ const usersRegisterValidator = [ | |||
56 | if (areValidationErrors(req, res)) return | 69 | if (areValidationErrors(req, res)) return |
57 | if (!await checkUserNameOrEmailDoesNotAlreadyExist(req.body.username, req.body.email, res)) return | 70 | if (!await checkUserNameOrEmailDoesNotAlreadyExist(req.body.username, req.body.email, res)) return |
58 | 71 | ||
72 | const body: UserRegister = req.body | ||
73 | if (body.channel) { | ||
74 | if (!body.channel.name || !body.channel.displayName) { | ||
75 | return res.status(400) | ||
76 | .send({ error: 'Channel is optional but if you specify it, channel.name and channel.displayName are required.' }) | ||
77 | .end() | ||
78 | } | ||
79 | |||
80 | if (body.channel.name === body.username) { | ||
81 | return res.status(400) | ||
82 | .send({ error: 'Channel name cannot be the same than user username.' }) | ||
83 | .end() | ||
84 | } | ||
85 | |||
86 | const existing = await ActorModel.loadLocalByName(body.channel.name) | ||
87 | if (existing) { | ||
88 | return res.status(409) | ||
89 | .send({ error: `Channel with name ${body.channel.name} already exists.` }) | ||
90 | .end() | ||
91 | } | ||
92 | } | ||
93 | |||
59 | return next() | 94 | return next() |
60 | } | 95 | } |
61 | ] | 96 | ] |
@@ -142,13 +177,27 @@ const usersUpdateValidator = [ | |||
142 | ] | 177 | ] |
143 | 178 | ||
144 | const usersUpdateMeValidator = [ | 179 | const usersUpdateMeValidator = [ |
145 | body('displayName').optional().custom(isUserDisplayNameValid).withMessage('Should have a valid display name'), | 180 | body('displayName') |
146 | body('description').optional().custom(isUserDescriptionValid).withMessage('Should have a valid description'), | 181 | .optional() |
147 | body('currentPassword').optional().custom(isUserPasswordValid).withMessage('Should have a valid current password'), | 182 | .custom(isUserDisplayNameValid).withMessage('Should have a valid display name'), |
148 | body('password').optional().custom(isUserPasswordValid).withMessage('Should have a valid password'), | 183 | body('description') |
149 | body('email').optional().isEmail().withMessage('Should have a valid email attribute'), | 184 | .optional() |
150 | body('nsfwPolicy').optional().custom(isUserNSFWPolicyValid).withMessage('Should have a valid display Not Safe For Work policy'), | 185 | .custom(isUserDescriptionValid).withMessage('Should have a valid description'), |
151 | body('autoPlayVideo').optional().custom(isUserAutoPlayVideoValid).withMessage('Should have a valid automatically plays video attribute'), | 186 | body('currentPassword') |
187 | .optional() | ||
188 | .custom(isUserPasswordValid).withMessage('Should have a valid current password'), | ||
189 | body('password') | ||
190 | .optional() | ||
191 | .custom(isUserPasswordValid).withMessage('Should have a valid password'), | ||
192 | body('email') | ||
193 | .optional() | ||
194 | .isEmail().withMessage('Should have a valid email attribute'), | ||
195 | body('nsfwPolicy') | ||
196 | .optional() | ||
197 | .custom(isUserNSFWPolicyValid).withMessage('Should have a valid display Not Safe For Work policy'), | ||
198 | body('autoPlayVideo') | ||
199 | .optional() | ||
200 | .custom(isUserAutoPlayVideoValid).withMessage('Should have a valid automatically plays video attribute'), | ||
152 | body('videosHistoryEnabled') | 201 | body('videosHistoryEnabled') |
153 | .optional() | 202 | .optional() |
154 | .custom(isUserVideosHistoryEnabledValid).withMessage('Should have a valid videos history enabled attribute'), | 203 | .custom(isUserVideosHistoryEnabledValid).withMessage('Should have a valid videos history enabled attribute'), |
@@ -156,7 +205,7 @@ const usersUpdateMeValidator = [ | |||
156 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 205 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
157 | logger.debug('Checking usersUpdateMe parameters', { parameters: omit(req.body, 'password') }) | 206 | logger.debug('Checking usersUpdateMe parameters', { parameters: omit(req.body, 'password') }) |
158 | 207 | ||
159 | if (req.body.password) { | 208 | if (req.body.password || req.body.email) { |
160 | if (!req.body.currentPassword) { | 209 | if (!req.body.currentPassword) { |
161 | return res.status(400) | 210 | return res.status(400) |
162 | .send({ error: 'currentPassword parameter is missing.' }) | 211 | .send({ error: 'currentPassword parameter is missing.' }) |
@@ -293,8 +342,14 @@ const usersAskSendVerifyEmailValidator = [ | |||
293 | ] | 342 | ] |
294 | 343 | ||
295 | const usersVerifyEmailValidator = [ | 344 | const usersVerifyEmailValidator = [ |
296 | param('id').isInt().not().isEmpty().withMessage('Should have a valid id'), | 345 | param('id') |
297 | body('verificationString').not().isEmpty().withMessage('Should have a valid verification string'), | 346 | .isInt().not().isEmpty().withMessage('Should have a valid id'), |
347 | |||
348 | body('verificationString') | ||
349 | .not().isEmpty().withMessage('Should have a valid verification string'), | ||
350 | body('isPendingEmail') | ||
351 | .optional() | ||
352 | .toBoolean(), | ||
298 | 353 | ||
299 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 354 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
300 | logger.debug('Checking usersVerifyEmail parameters', { parameters: req.params }) | 355 | logger.debug('Checking usersVerifyEmail parameters', { parameters: req.params }) |
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' | |||
14 | import { areValidationErrors } from '../utils' | 14 | import { areValidationErrors } from '../utils' |
15 | import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor' | 15 | import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor' |
16 | import { ActorModel } from '../../../models/activitypub/actor' | 16 | import { ActorModel } from '../../../models/activitypub/actor' |
17 | import { isBooleanValid } from '../../../helpers/custom-validators/misc' | ||
17 | 18 | ||
18 | const videoChannelsAddValidator = [ | 19 | const 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 | ||
41 | const videoChannelsUpdateValidator = [ | 42 | const 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/ | |||
24 | import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model' | 24 | import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model' |
25 | 25 | ||
26 | const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([ | 26 | const 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/account/user.ts b/server/models/account/user.ts index 4a9acd703..e75039521 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts | |||
@@ -114,6 +114,11 @@ export class UserModel extends Model<UserModel> { | |||
114 | email: string | 114 | email: string |
115 | 115 | ||
116 | @AllowNull(true) | 116 | @AllowNull(true) |
117 | @IsEmail | ||
118 | @Column(DataType.STRING(400)) | ||
119 | pendingEmail: string | ||
120 | |||
121 | @AllowNull(true) | ||
117 | @Default(null) | 122 | @Default(null) |
118 | @Is('UserEmailVerified', value => throwIfNotValid(value, isUserEmailVerifiedValid, 'email verified boolean', true)) | 123 | @Is('UserEmailVerified', value => throwIfNotValid(value, isUserEmailVerifiedValid, 'email verified boolean', true)) |
119 | @Column | 124 | @Column |
@@ -540,6 +545,7 @@ export class UserModel extends Model<UserModel> { | |||
540 | id: this.id, | 545 | id: this.id, |
541 | username: this.username, | 546 | username: this.username, |
542 | email: this.email, | 547 | email: this.email, |
548 | pendingEmail: this.pendingEmail, | ||
543 | emailVerified: this.emailVerified, | 549 | emailVerified: this.emailVerified, |
544 | nsfwPolicy: this.nsfwPolicy, | 550 | nsfwPolicy: this.nsfwPolicy, |
545 | webTorrentEnabled: this.webTorrentEnabled, | 551 | webTorrentEnabled: this.webTorrentEnabled, |
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' | |||
24 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' | 24 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' |
25 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' | 25 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' |
26 | import { FindOptions, QueryTypes, Transaction } from 'sequelize' | 26 | import { FindOptions, QueryTypes, Transaction } from 'sequelize' |
27 | import { 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 @@ | |||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
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 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
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 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
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 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
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 | ||
19 | const expect = chai.expect | 19 | const expect = chai.expect |
20 | 20 | ||
21 | function setKeysOfServer2 (serverNumber: number, publicKey: string, privateKey: string) { | 21 | function 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 | ||
28 | function setKeysOfServer3 (serverNumber: number, publicKey: string, privateKey: string) { | 28 | function 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 | ||
35 | describe('Test ActivityPub security', function () { | 43 | describe('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..a0d9392dc 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts | |||
@@ -59,13 +59,15 @@ 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, |
65 | '360p': true, | 66 | '360p': true, |
66 | '480p': true, | 67 | '480p': true, |
67 | '720p': false, | 68 | '720p': false, |
68 | '1080p': false | 69 | '1080p': false, |
70 | '2160p': false | ||
69 | }, | 71 | }, |
70 | hls: { | 72 | hls: { |
71 | enabled: false | 73 | enabled: false |
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index 5935104a5..2316033a1 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' | |||
6 | import { UserRole, VideoImport, VideoImportState } from '../../../../shared' | 6 | import { UserRole, VideoImport, VideoImportState } from '../../../../shared' |
7 | 7 | ||
8 | import { | 8 | import { |
9 | addVideoChannel, | ||
9 | blockUser, | 10 | blockUser, |
10 | cleanupTests, | 11 | cleanupTests, |
11 | createUser, | 12 | createUser, |
@@ -378,8 +379,7 @@ describe('Test users API validators', function () { | |||
378 | it('Should succeed without password change with the correct params', async function () { | 379 | it('Should succeed without password change with the correct params', async function () { |
379 | const fields = { | 380 | const fields = { |
380 | nsfwPolicy: 'blur', | 381 | nsfwPolicy: 'blur', |
381 | autoPlayVideo: false, | 382 | autoPlayVideo: false |
382 | email: 'super_email@example.com' | ||
383 | } | 383 | } |
384 | 384 | ||
385 | await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields, statusCodeExpected: 204 }) | 385 | await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields, statusCodeExpected: 204 }) |
@@ -638,10 +638,11 @@ describe('Test users API validators', function () { | |||
638 | }) | 638 | }) |
639 | }) | 639 | }) |
640 | 640 | ||
641 | describe('When register a new user', function () { | 641 | describe('When registering a new user', function () { |
642 | const registrationPath = path + '/register' | 642 | const registrationPath = path + '/register' |
643 | const baseCorrectParams = { | 643 | const baseCorrectParams = { |
644 | username: 'user3', | 644 | username: 'user3', |
645 | displayName: 'super user', | ||
645 | email: 'test3@example.com', | 646 | email: 'test3@example.com', |
646 | password: 'my super password' | 647 | password: 'my super password' |
647 | } | 648 | } |
@@ -724,12 +725,48 @@ describe('Test users API validators', function () { | |||
724 | }) | 725 | }) |
725 | }) | 726 | }) |
726 | 727 | ||
728 | it('Should fail with a bad display name', async function () { | ||
729 | const fields = immutableAssign(baseCorrectParams, { displayName: 'a'.repeat(150) }) | ||
730 | |||
731 | await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields }) | ||
732 | }) | ||
733 | |||
734 | it('Should fail with a bad channel name', async function () { | ||
735 | const fields = immutableAssign(baseCorrectParams, { channel: { name: '[]azf', displayName: 'toto' } }) | ||
736 | |||
737 | await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields }) | ||
738 | }) | ||
739 | |||
740 | it('Should fail with a bad channel display name', async function () { | ||
741 | const fields = immutableAssign(baseCorrectParams, { channel: { name: 'toto', displayName: '' } }) | ||
742 | |||
743 | await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields }) | ||
744 | }) | ||
745 | |||
746 | it('Should fail with a channel name that is the same than user username', async function () { | ||
747 | const source = { username: 'super_user', channel: { name: 'super_user', displayName: 'display name' } } | ||
748 | const fields = immutableAssign(baseCorrectParams, source) | ||
749 | |||
750 | await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields }) | ||
751 | }) | ||
752 | |||
753 | it('Should fail with an existing channel', async function () { | ||
754 | const videoChannelAttributesArg = { name: 'existing_channel', displayName: 'hello', description: 'super description' } | ||
755 | await addVideoChannel(server.url, server.accessToken, videoChannelAttributesArg) | ||
756 | |||
757 | const fields = immutableAssign(baseCorrectParams, { channel: { name: 'existing_channel', displayName: 'toto' } }) | ||
758 | |||
759 | await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields, statusCodeExpected: 409 }) | ||
760 | }) | ||
761 | |||
727 | it('Should succeed with the correct params', async function () { | 762 | it('Should succeed with the correct params', async function () { |
763 | const fields = immutableAssign(baseCorrectParams, { channel: { name: 'super_channel', displayName: 'toto' } }) | ||
764 | |||
728 | await makePostBodyRequest({ | 765 | await makePostBodyRequest({ |
729 | url: server.url, | 766 | url: server.url, |
730 | path: registrationPath, | 767 | path: registrationPath, |
731 | token: server.accessToken, | 768 | token: server.accessToken, |
732 | fields: baseCorrectParams, | 769 | fields: fields, |
733 | statusCodeExpected: 204 | 770 | statusCodeExpected: 204 |
734 | }) | 771 | }) |
735 | }) | 772 | }) |
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' |
26 | import { join } from 'path' | 26 | import { join } from 'path' |
27 | import { VideoChannelUpdate } from '../../../../shared/models/videos' | ||
27 | 28 | ||
28 | const expect = chai.expect | 29 | const 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 @@ | |||
1 | import './check-params' | ||
2 | import './notifications' | ||
3 | import './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 @@ | |||
1 | import './server' | ||
2 | import './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 @@ | |||
1 | import './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 @@ | |||
1 | import './redundancy' | ||
2 | import './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 |
2 | import './index-1' | 2 | import './activitypub' |
3 | import './index-2' | 3 | import './check-params' |
4 | import './index-3' | 4 | import './notifications' |
5 | import './index-4' | 5 | import './redundancy' |
6 | import './search' | ||
7 | import './server' | ||
8 | import './users' | ||
9 | import './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 @@ | |||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
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 | ||
25 | const expect = chai.expect | 26 | const expect = chai.expect |
26 | 27 | ||
27 | describe('Test a ActivityPub video channels search', function () { | 28 | describe('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' | |||
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
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' |
20 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 19 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
21 | import { Video, VideoPrivacy } from '../../../../shared/models/videos' | 20 | import { Video, VideoPrivacy } from '../../../../shared/models/videos' |
22 | 21 | ||
23 | const expect = chai.expect | 22 | const expect = chai.expect |
24 | 23 | ||
25 | describe('Test a ActivityPub videos search', function () { | 24 | describe('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' | |||
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
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 | ||
19 | const expect = chai.expect | 17 | const expect = chai.expect |
20 | 18 | ||
21 | describe('Test a videos search', function () { | 19 | describe('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..c39516dee 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' |
20 | import { ServerConfig } from '../../../../shared/models' | 20 | import { ServerConfig } from '../../../../shared/models' |
21 | 21 | ||
22 | const expect = chai.expect | 22 | const expect = chai.expect |
23 | 23 | ||
24 | function checkInitialConfig (data: CustomConfig) { | 24 | function 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,19 +45,21 @@ 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 |
58 | expect(data.transcoding.resolutions['480p']).to.be.true | 59 | expect(data.transcoding.resolutions['480p']).to.be.true |
59 | expect(data.transcoding.resolutions['720p']).to.be.true | 60 | expect(data.transcoding.resolutions['720p']).to.be.true |
60 | expect(data.transcoding.resolutions['1080p']).to.be.true | 61 | expect(data.transcoding.resolutions['1080p']).to.be.true |
62 | expect(data.transcoding.resolutions['2160p']).to.be.true | ||
61 | expect(data.transcoding.hls.enabled).to.be.true | 63 | expect(data.transcoding.hls.enabled).to.be.true |
62 | 64 | ||
63 | expect(data.import.videos.http.enabled).to.be.true | 65 | expect(data.import.videos.http.enabled).to.be.true |
@@ -89,7 +91,11 @@ function checkUpdatedConfig (data: CustomConfig) { | |||
89 | expect(data.signup.limit).to.equal(5) | 91 | expect(data.signup.limit).to.equal(5) |
90 | expect(data.signup.requiresEmailVerification).to.be.false | 92 | expect(data.signup.requiresEmailVerification).to.be.false |
91 | 93 | ||
92 | expect(data.admin.email).to.equal('superadmin1@example.com') | 94 | // We override admin email in parallel tests, so skip this exception |
95 | if (parallelTests() === false) { | ||
96 | expect(data.admin.email).to.equal('superadmin1@example.com') | ||
97 | } | ||
98 | |||
93 | expect(data.contactForm.enabled).to.be.false | 99 | expect(data.contactForm.enabled).to.be.false |
94 | 100 | ||
95 | expect(data.user.videoQuota).to.equal(5242881) | 101 | expect(data.user.videoQuota).to.equal(5242881) |
@@ -98,11 +104,13 @@ function checkUpdatedConfig (data: CustomConfig) { | |||
98 | expect(data.transcoding.enabled).to.be.true | 104 | expect(data.transcoding.enabled).to.be.true |
99 | expect(data.transcoding.threads).to.equal(1) | 105 | expect(data.transcoding.threads).to.equal(1) |
100 | expect(data.transcoding.allowAdditionalExtensions).to.be.true | 106 | expect(data.transcoding.allowAdditionalExtensions).to.be.true |
107 | expect(data.transcoding.allowAudioFiles).to.be.true | ||
101 | expect(data.transcoding.resolutions['240p']).to.be.false | 108 | expect(data.transcoding.resolutions['240p']).to.be.false |
102 | expect(data.transcoding.resolutions['360p']).to.be.true | 109 | expect(data.transcoding.resolutions['360p']).to.be.true |
103 | expect(data.transcoding.resolutions['480p']).to.be.true | 110 | expect(data.transcoding.resolutions['480p']).to.be.true |
104 | expect(data.transcoding.resolutions['720p']).to.be.false | 111 | expect(data.transcoding.resolutions['720p']).to.be.false |
105 | expect(data.transcoding.resolutions['1080p']).to.be.false | 112 | expect(data.transcoding.resolutions['1080p']).to.be.false |
113 | expect(data.transcoding.resolutions['2160p']).to.be.false | ||
106 | expect(data.transcoding.hls.enabled).to.be.false | 114 | expect(data.transcoding.hls.enabled).to.be.false |
107 | 115 | ||
108 | expect(data.import.videos.http.enabled).to.be.false | 116 | expect(data.import.videos.http.enabled).to.be.false |
@@ -118,6 +126,7 @@ describe('Test config', function () { | |||
118 | 126 | ||
119 | before(async function () { | 127 | before(async function () { |
120 | this.timeout(30000) | 128 | this.timeout(30000) |
129 | |||
121 | server = await flushAndRunServer(1) | 130 | server = await flushAndRunServer(1) |
122 | await setAccessTokensToServers([ server ]) | 131 | await setAccessTokensToServers([ server ]) |
123 | }) | 132 | }) |
@@ -153,6 +162,9 @@ describe('Test config', function () { | |||
153 | expect(data.video.file.extensions).to.contain('.webm') | 162 | expect(data.video.file.extensions).to.contain('.webm') |
154 | expect(data.video.file.extensions).to.contain('.ogv') | 163 | expect(data.video.file.extensions).to.contain('.ogv') |
155 | 164 | ||
165 | await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, 400) | ||
166 | await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, 400) | ||
167 | |||
156 | expect(data.contactForm.enabled).to.be.true | 168 | expect(data.contactForm.enabled).to.be.true |
157 | }) | 169 | }) |
158 | 170 | ||
@@ -160,7 +172,7 @@ describe('Test config', function () { | |||
160 | const res = await getCustomConfig(server.url, server.accessToken) | 172 | const res = await getCustomConfig(server.url, server.accessToken) |
161 | const data = res.body as CustomConfig | 173 | const data = res.body as CustomConfig |
162 | 174 | ||
163 | checkInitialConfig(data) | 175 | checkInitialConfig(server, data) |
164 | }) | 176 | }) |
165 | 177 | ||
166 | it('Should update the customized configuration', async function () { | 178 | it('Should update the customized configuration', async function () { |
@@ -210,13 +222,15 @@ describe('Test config', function () { | |||
210 | transcoding: { | 222 | transcoding: { |
211 | enabled: true, | 223 | enabled: true, |
212 | allowAdditionalExtensions: true, | 224 | allowAdditionalExtensions: true, |
225 | allowAudioFiles: true, | ||
213 | threads: 1, | 226 | threads: 1, |
214 | resolutions: { | 227 | resolutions: { |
215 | '240p': false, | 228 | '240p': false, |
216 | '360p': true, | 229 | '360p': true, |
217 | '480p': true, | 230 | '480p': true, |
218 | '720p': false, | 231 | '720p': false, |
219 | '1080p': false | 232 | '1080p': false, |
233 | '2160p': false | ||
220 | }, | 234 | }, |
221 | hls: { | 235 | hls: { |
222 | enabled: false | 236 | enabled: false |
@@ -264,6 +278,12 @@ describe('Test config', function () { | |||
264 | expect(data.video.file.extensions).to.contain('.ogv') | 278 | expect(data.video.file.extensions).to.contain('.ogv') |
265 | expect(data.video.file.extensions).to.contain('.flv') | 279 | expect(data.video.file.extensions).to.contain('.flv') |
266 | expect(data.video.file.extensions).to.contain('.mkv') | 280 | expect(data.video.file.extensions).to.contain('.mkv') |
281 | expect(data.video.file.extensions).to.contain('.mp3') | ||
282 | expect(data.video.file.extensions).to.contain('.ogg') | ||
283 | expect(data.video.file.extensions).to.contain('.flac') | ||
284 | |||
285 | await uploadVideo(server.url, server.accessToken, { fixture: 'video_short.mkv' }, 200) | ||
286 | await uploadVideo(server.url, server.accessToken, { fixture: 'sample.ogg' }, 200) | ||
267 | }) | 287 | }) |
268 | 288 | ||
269 | it('Should have the configuration updated after a restart', async function () { | 289 | it('Should have the configuration updated after a restart', async function () { |
@@ -297,7 +317,7 @@ describe('Test config', function () { | |||
297 | const res = await getCustomConfig(server.url, server.accessToken) | 317 | const res = await getCustomConfig(server.url, server.accessToken) |
298 | const data = res.body | 318 | const data = res.body |
299 | 319 | ||
300 | checkInitialConfig(data) | 320 | checkInitialConfig(server, data) |
301 | }) | 321 | }) |
302 | 322 | ||
303 | after(async function () { | 323 | 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..7b7acfd12 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' |
23 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' | 23 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' |
24 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 24 | import { 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') |
@@ -248,7 +250,7 @@ describe('Test emails', function () { | |||
248 | }) | 250 | }) |
249 | 251 | ||
250 | it('Should not verify the email with an invalid verification string', async function () { | 252 | it('Should not verify the email with an invalid verification string', async function () { |
251 | await verifyEmail(server.url, userId, verificationString + 'b', 403) | 253 | await verifyEmail(server.url, userId, verificationString + 'b', false, 403) |
252 | }) | 254 | }) |
253 | 255 | ||
254 | it('Should verify the email', async function () { | 256 | it('Should verify the email', async function () { |
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 @@ | |||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
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' |
17 | import { unfollow } from '../../../../shared/extra-utils/server/follows' | 17 | import { unfollow } from '../../../../shared/extra-utils/server/follows' |
18 | import { userLogin } from '../../../../shared/extra-utils/users/login' | 18 | import { 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 @@ | |||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
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' |
20 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 20 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
21 | import { ActorFollow } from '../../../../shared/models/actors' | 21 | import { 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 | |||
8 | import { | 8 | import { |
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 | |||
3 | set -eu | ||
4 | |||
5 | checkParamFiles=$(find server/tests/api/check-params -type f | grep -v index.ts | xargs echo) | ||
6 | notificationsFiles=$(find server/tests/api/notifications -type f | grep -v index.ts | xargs echo) | ||
7 | searchFiles=$(find server/tests/api/search -type f | grep -v index.ts | xargs echo) | ||
8 | |||
9 | MOCHA_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 | |||
3 | set -eu | ||
4 | |||
5 | serverFiles=$(find server/tests/api/server -type f | grep -v index.ts | xargs echo) | ||
6 | usersFiles=$(find server/tests/api/users -type f | grep -v index.ts | xargs echo) | ||
7 | |||
8 | MOCHA_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 | |||
3 | set -eu | ||
4 | |||
5 | videosFiles=$(find server/tests/api/videos -type f | grep -v index.ts | xargs echo) | ||
6 | |||
7 | MOCHA_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 | |||
3 | set -eu | ||
4 | |||
5 | redundancyFiles=$(find server/tests/api/redundancy -type f | grep -v index.ts | xargs echo) | ||
6 | activitypubFiles=$(find server/tests/api/activitypub -type f | grep -v index.ts | xargs echo) | ||
7 | |||
8 | MOCHA_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' | |||
5 | import { Account } from '../../../../shared/models/actors' | 5 | import { Account } from '../../../../shared/models/actors' |
6 | import { | 6 | import { |
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' |
18 | import { | 19 | import { 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' | ||
26 | import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../../../shared/extra-utils/users/accounts' | 20 | import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../../../shared/extra-utils/users/accounts' |
27 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' | 21 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' |
28 | import { User } from '../../../../shared/models/users' | 22 | import { User } from '../../../../shared/models/users' |
@@ -34,12 +28,10 @@ const expect = chai.expect | |||
34 | describe('Test users with multiple servers', function () { | 28 | describe('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..7cd61f539 100644 --- a/server/tests/api/users/users-verification.ts +++ b/server/tests/api/users/users-verification.ts | |||
@@ -3,18 +3,29 @@ | |||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | registerUser, flushTests, getUserInformation, getMyUserInformation, killallServers, | 6 | cleanupTests, |
7 | userLogin, login, flushAndRunServer, ServerInfo, verifyEmail, updateCustomSubConfig, wait, cleanupTests | 7 | flushAndRunServer, |
8 | getMyUserInformation, | ||
9 | getUserInformation, | ||
10 | login, | ||
11 | registerUser, | ||
12 | ServerInfo, | ||
13 | updateCustomSubConfig, | ||
14 | updateMyUser, | ||
15 | userLogin, | ||
16 | verifyEmail | ||
8 | } from '../../../../shared/extra-utils' | 17 | } from '../../../../shared/extra-utils' |
9 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' | 18 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' |
10 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' | 19 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' |
11 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 20 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
21 | import { User } from '../../../../shared/models/users' | ||
12 | 22 | ||
13 | const expect = chai.expect | 23 | const expect = chai.expect |
14 | 24 | ||
15 | describe('Test users account verification', function () { | 25 | describe('Test users account verification', function () { |
16 | let server: ServerInfo | 26 | let server: ServerInfo |
17 | let userId: number | 27 | let userId: number |
28 | let userAccessToken: string | ||
18 | let verificationString: string | 29 | let verificationString: string |
19 | let expectedEmailsLength = 0 | 30 | let expectedEmailsLength = 0 |
20 | const user1 = { | 31 | const user1 = { |
@@ -30,11 +41,12 @@ describe('Test users account verification', function () { | |||
30 | before(async function () { | 41 | before(async function () { |
31 | this.timeout(30000) | 42 | this.timeout(30000) |
32 | 43 | ||
33 | await MockSmtpServer.Instance.collectEmails(emails) | 44 | const port = await MockSmtpServer.Instance.collectEmails(emails) |
34 | 45 | ||
35 | const overrideConfig = { | 46 | const overrideConfig = { |
36 | smtp: { | 47 | smtp: { |
37 | hostname: 'localhost' | 48 | hostname: 'localhost', |
49 | port | ||
38 | } | 50 | } |
39 | } | 51 | } |
40 | server = await flushAndRunServer(1, overrideConfig) | 52 | server = await flushAndRunServer(1, overrideConfig) |
@@ -82,11 +94,54 @@ describe('Test users account verification', function () { | |||
82 | 94 | ||
83 | it('Should verify the user via email and allow login', async function () { | 95 | it('Should verify the user via email and allow login', async function () { |
84 | await verifyEmail(server.url, userId, verificationString) | 96 | await verifyEmail(server.url, userId, verificationString) |
85 | await login(server.url, server.client, user1) | 97 | |
98 | const res = await login(server.url, server.client, user1) | ||
99 | userAccessToken = res.body.access_token | ||
100 | |||
86 | const resUserVerified = await getUserInformation(server.url, server.accessToken, userId) | 101 | const resUserVerified = await getUserInformation(server.url, server.accessToken, userId) |
87 | expect(resUserVerified.body.emailVerified).to.be.true | 102 | expect(resUserVerified.body.emailVerified).to.be.true |
88 | }) | 103 | }) |
89 | 104 | ||
105 | it('Should be able to change the user email', async function () { | ||
106 | let updateVerificationString: string | ||
107 | |||
108 | { | ||
109 | await updateMyUser({ | ||
110 | url: server.url, | ||
111 | accessToken: userAccessToken, | ||
112 | email: 'updated@example.com', | ||
113 | currentPassword: user1.password | ||
114 | }) | ||
115 | |||
116 | await waitJobs(server) | ||
117 | expectedEmailsLength++ | ||
118 | expect(emails).to.have.lengthOf(expectedEmailsLength) | ||
119 | |||
120 | const email = emails[expectedEmailsLength - 1] | ||
121 | |||
122 | const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) | ||
123 | updateVerificationString = verificationStringMatches[1] | ||
124 | } | ||
125 | |||
126 | { | ||
127 | const res = await getMyUserInformation(server.url, userAccessToken) | ||
128 | const me: User = res.body | ||
129 | |||
130 | expect(me.email).to.equal('user_1@example.com') | ||
131 | expect(me.pendingEmail).to.equal('updated@example.com') | ||
132 | } | ||
133 | |||
134 | { | ||
135 | await verifyEmail(server.url, userId, updateVerificationString, true) | ||
136 | |||
137 | const res = await getMyUserInformation(server.url, userAccessToken) | ||
138 | const me: User = res.body | ||
139 | |||
140 | expect(me.email).to.equal('updated@example.com') | ||
141 | expect(me.pendingEmail).to.be.null | ||
142 | } | ||
143 | }) | ||
144 | |||
90 | it('Should register user not requiring email verification if setting not enabled', async function () { | 145 | it('Should register user not requiring email verification if setting not enabled', async function () { |
91 | this.timeout(5000) | 146 | this.timeout(5000) |
92 | await updateCustomSubConfig(server.url, server.accessToken, { | 147 | await updateCustomSubConfig(server.url, server.accessToken, { |
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index c8e32f3f5..403d1a089 100644 --- a/server/tests/api/users/users.ts +++ b/server/tests/api/users/users.ts | |||
@@ -17,11 +17,12 @@ import { | |||
17 | getUserInformation, | 17 | getUserInformation, |
18 | getUsersList, | 18 | getUsersList, |
19 | getUsersListPaginationAndSort, | 19 | getUsersListPaginationAndSort, |
20 | getVideoChannel, | ||
20 | getVideosList, | 21 | getVideosList, |
21 | login, | 22 | login, |
22 | makePutBodyRequest, | 23 | makePutBodyRequest, |
23 | rateVideo, | 24 | rateVideo, |
24 | registerUser, | 25 | registerUserWithChannel, |
25 | removeUser, | 26 | removeUser, |
26 | removeVideo, | 27 | removeVideo, |
27 | ServerInfo, | 28 | ServerInfo, |
@@ -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') |
@@ -467,10 +468,11 @@ describe('Test users', function () { | |||
467 | expect(user.autoPlayVideo).to.be.false | 468 | expect(user.autoPlayVideo).to.be.false |
468 | }) | 469 | }) |
469 | 470 | ||
470 | it('Should be able to change the email display attribute', async function () { | 471 | it('Should be able to change the email attribute', async function () { |
471 | await updateMyUser({ | 472 | await updateMyUser({ |
472 | url: server.url, | 473 | url: server.url, |
473 | accessToken: accessTokenUser, | 474 | accessToken: accessTokenUser, |
475 | currentPassword: 'new password', | ||
474 | email: 'updated@example.com' | 476 | email: 'updated@example.com' |
475 | }) | 477 | }) |
476 | 478 | ||
@@ -617,7 +619,10 @@ describe('Test users', function () { | |||
617 | 619 | ||
618 | describe('Registering a new user', function () { | 620 | describe('Registering a new user', function () { |
619 | it('Should register a new user', async function () { | 621 | it('Should register a new user', async function () { |
620 | await registerUser(server.url, 'user_15', 'my super password') | 622 | const user = { displayName: 'super user 15', username: 'user_15', password: 'my super password' } |
623 | const channel = { name: 'my_user_15_channel', displayName: 'my channel rocks' } | ||
624 | |||
625 | await registerUserWithChannel({ url: server.url, user, channel }) | ||
621 | }) | 626 | }) |
622 | 627 | ||
623 | it('Should be able to login with this registered user', async function () { | 628 | it('Should be able to login with this registered user', async function () { |
@@ -629,6 +634,13 @@ describe('Test users', function () { | |||
629 | accessToken = await userLogin(server, user15) | 634 | accessToken = await userLogin(server, user15) |
630 | }) | 635 | }) |
631 | 636 | ||
637 | it('Should have the correct display name', async function () { | ||
638 | const res = await getMyUserInformation(server.url, accessToken) | ||
639 | const user: User = res.body | ||
640 | |||
641 | expect(user.account.displayName).to.equal('super user 15') | ||
642 | }) | ||
643 | |||
632 | it('Should have the correct video quota', async function () { | 644 | it('Should have the correct video quota', async function () { |
633 | const res = await getMyUserInformation(server.url, accessToken) | 645 | const res = await getMyUserInformation(server.url, accessToken) |
634 | const user = res.body | 646 | const user = res.body |
@@ -636,6 +648,12 @@ describe('Test users', function () { | |||
636 | expect(user.videoQuota).to.equal(5 * 1024 * 1024) | 648 | expect(user.videoQuota).to.equal(5 * 1024 * 1024) |
637 | }) | 649 | }) |
638 | 650 | ||
651 | it('Should have created the channel', async function () { | ||
652 | const res = await getVideoChannel(server.url, 'my_user_15_channel') | ||
653 | |||
654 | expect(res.body.displayName).to.equal('my channel rocks') | ||
655 | }) | ||
656 | |||
639 | it('Should remove me', async function () { | 657 | it('Should remove me', async function () { |
640 | { | 658 | { |
641 | const res = await getUsersList(server.url, server.accessToken) | 659 | 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/ | |||
9 | import { | 9 | import { |
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' | |||
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
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 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { User, Video } from '../../../../shared/index' | 5 | import { User, Video, VideoChannel, VideoDetails } from '../../../../shared/index' |
6 | import { | 6 | import { |
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 { | |||
18 | import { | 18 | import { |
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 | |||
35 | describe('Test video channels', function () { | 33 | describe('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' | |||
5 | import { | 5 | import { |
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 { | |||
22 | import { VideoDetails } from '../../../../shared/models/videos' | 21 | import { VideoDetails } from '../../../../shared/models/videos' |
23 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' | 22 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' |
24 | import { join } from 'path' | 23 | import { join } from 'path' |
24 | import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' | ||
25 | 25 | ||
26 | const expect = chai.expect | 26 | const expect = chai.expect |
27 | 27 | ||
28 | async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string) { | 28 | async 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) { | |||
71 | describe('Test HLS videos', function () { | 68 | describe('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..f82c8cbce 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,39 @@ describe('Test video playlists', function () { | |||
754 | } | 754 | } |
755 | }) | 755 | }) |
756 | 756 | ||
757 | it('Should be able to create a public playlist, and set it to private', async function () { | ||
758 | this.timeout(30000) | ||
759 | |||
760 | const res = await createVideoPlaylist({ | ||
761 | url: servers[0].url, | ||
762 | token: servers[0].accessToken, | ||
763 | playlistAttrs: { | ||
764 | displayName: 'my super public playlist', | ||
765 | privacy: VideoPlaylistPrivacy.PUBLIC, | ||
766 | videoChannelId: servers[0].videoChannel.id | ||
767 | } | ||
768 | }) | ||
769 | const videoPlaylistIds = res.body.videoPlaylist | ||
770 | |||
771 | await waitJobs(servers) | ||
772 | |||
773 | for (const server of servers) { | ||
774 | await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 200) | ||
775 | } | ||
776 | |||
777 | const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE } | ||
778 | await updateVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs }) | ||
779 | |||
780 | await waitJobs(servers) | ||
781 | |||
782 | for (const server of [ servers[1], servers[2] ]) { | ||
783 | await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404) | ||
784 | } | ||
785 | await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, 401) | ||
786 | |||
787 | await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, 200) | ||
788 | }) | ||
789 | |||
757 | it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () { | 790 | it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () { |
758 | this.timeout(30000) | 791 | this.timeout(30000) |
759 | 792 | ||
@@ -770,7 +803,7 @@ describe('Test video playlists', function () { | |||
770 | this.timeout(30000) | 803 | this.timeout(30000) |
771 | 804 | ||
772 | for (const server of servers) { | 805 | for (const server of servers) { |
773 | await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.serverNumber) | 806 | await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.internalServerNumber) |
774 | } | 807 | } |
775 | }) | 808 | }) |
776 | 809 | ||
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 | |||
6 | import { | 6 | import { |
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' | |||
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { omit } from 'lodash' | 5 | import { omit } from 'lodash' |
6 | import { getMaxBitrate, VideoDetails, VideoResolution, VideoState } from '../../../../shared/models/videos' | 6 | import { getMaxBitrate, VideoDetails, VideoResolution, VideoState } from '../../../../shared/models/videos' |
7 | import { audio, getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' | 7 | import { audio, canDoQuickTranscode, getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' |
8 | import { | 8 | import { |
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' |
23 | import { extname, join } from 'path' | 25 | import { join } from 'path' |
24 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | ||
25 | import { VIDEO_TRANSCODING_FPS } from '../../../../server/initializers/constants' | 26 | import { VIDEO_TRANSCODING_FPS } from '../../../../server/initializers/constants' |
26 | 27 | ||
27 | const expect = chai.expect | 28 | const 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' |
15 | import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews' | 15 | import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews' |
16 | import { VideosOverview } from '../../../../shared/models/overviews' | 16 | import { 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' |
20 | import { waitJobs } from '../../../shared/extra-utils/server/jobs' | 22 | import { waitJobs } from '../../../shared/extra-utils/server/jobs' |
21 | import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../helpers/ffmpeg-utils' | 23 | import { 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/cli/peertube.ts b/server/tests/cli/peertube.ts index 80bbc98d5..d73e27564 100644 --- a/server/tests/cli/peertube.ts +++ b/server/tests/cli/peertube.ts | |||
@@ -1,28 +1,46 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | ||
2 | |||
1 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | ||
2 | import { | 5 | import { |
3 | expect | 6 | addVideoChannel, |
4 | } from 'chai' | 7 | buildAbsoluteFixturePath, |
5 | import { | 8 | cleanupTests, |
6 | createUser, | 9 | createUser, |
7 | execCLI, | 10 | execCLI, |
8 | flushTests, | ||
9 | getEnvCli, | ||
10 | killallServers, | ||
11 | flushAndRunServer, | 11 | flushAndRunServer, |
12 | getEnvCli, | ||
13 | getVideo, | ||
14 | getVideosList, | ||
15 | getVideosListWithToken, removeVideo, | ||
12 | ServerInfo, | 16 | ServerInfo, |
13 | setAccessTokensToServers, cleanupTests | 17 | setAccessTokensToServers, |
18 | userLogin, | ||
19 | waitJobs | ||
14 | } from '../../../shared/extra-utils' | 20 | } from '../../../shared/extra-utils' |
21 | import { Video, VideoDetails } from '../../../shared' | ||
22 | import { getYoutubeVideoUrl } from '../../../shared/extra-utils/videos/video-imports' | ||
15 | 23 | ||
16 | describe('Test CLI wrapper', function () { | 24 | describe('Test CLI wrapper', function () { |
17 | let server: ServerInfo | 25 | let server: ServerInfo |
26 | let userAccessToken: string | ||
27 | |||
18 | const cmd = 'node ./dist/server/tools/peertube.js' | 28 | const cmd = 'node ./dist/server/tools/peertube.js' |
19 | 29 | ||
20 | before(async function () { | 30 | before(async function () { |
21 | this.timeout(30000) | 31 | this.timeout(30000) |
32 | |||
22 | server = await flushAndRunServer(1) | 33 | server = await flushAndRunServer(1) |
23 | await setAccessTokensToServers([ server ]) | 34 | await setAccessTokensToServers([ server ]) |
24 | 35 | ||
25 | await createUser({ url: server.url, accessToken: server.accessToken, username: 'user_1', password: 'super password' }) | 36 | await createUser({ url: server.url, accessToken: server.accessToken, username: 'user_1', password: 'super_password' }) |
37 | |||
38 | userAccessToken = await userLogin(server, { username: 'user_1', password: 'super_password' }) | ||
39 | |||
40 | { | ||
41 | const args = { name: 'user_channel', displayName: 'User channel', support: 'super support text' } | ||
42 | await addVideoChannel(server.url, userAccessToken, args) | ||
43 | } | ||
26 | }) | 44 | }) |
27 | 45 | ||
28 | it('Should display no selected instance', async function () { | 46 | it('Should display no selected instance', async function () { |
@@ -31,21 +49,132 @@ describe('Test CLI wrapper', function () { | |||
31 | const env = getEnvCli(server) | 49 | const env = getEnvCli(server) |
32 | const stdout = await execCLI(`${env} ${cmd} --help`) | 50 | const stdout = await execCLI(`${env} ${cmd} --help`) |
33 | 51 | ||
34 | expect(stdout).to.contain('selected') | 52 | expect(stdout).to.contain('no instance selected') |
53 | }) | ||
54 | |||
55 | it('Should add a user', async function () { | ||
56 | this.timeout(60000) | ||
57 | |||
58 | const env = getEnvCli(server) | ||
59 | await execCLI(`${env} ${cmd} auth add -u ${server.url} -U user_1 -p super_password`) | ||
60 | }) | ||
61 | |||
62 | it('Should default to this user', async function () { | ||
63 | this.timeout(60000) | ||
64 | |||
65 | const env = getEnvCli(server) | ||
66 | const stdout = await execCLI(`${env} ${cmd} --help`) | ||
67 | |||
68 | expect(stdout).to.contain(`instance ${server.url} selected`) | ||
69 | }) | ||
70 | |||
71 | it('Should remember the user', async function () { | ||
72 | this.timeout(60000) | ||
73 | |||
74 | const env = getEnvCli(server) | ||
75 | const stdout = await execCLI(`${env} ${cmd} auth list`) | ||
76 | |||
77 | expect(stdout).to.contain(server.url) | ||
78 | }) | ||
79 | |||
80 | it('Should upload a video', async function () { | ||
81 | this.timeout(60000) | ||
82 | |||
83 | const env = getEnvCli(server) | ||
84 | |||
85 | const fixture = buildAbsoluteFixturePath('60fps_720p_small.mp4') | ||
86 | |||
87 | const params = `-f ${fixture} --video-name 'test upload' --channel-name user_channel --support 'support_text'` | ||
88 | |||
89 | await execCLI(`${env} ${cmd} upload ${params}`) | ||
90 | }) | ||
91 | |||
92 | it('Should have the video uploaded', async function () { | ||
93 | const res = await getVideosList(server.url) | ||
94 | |||
95 | expect(res.body.total).to.equal(1) | ||
96 | |||
97 | const videos: Video[] = res.body.data | ||
98 | |||
99 | const video: VideoDetails = (await getVideo(server.url, videos[0].uuid)).body | ||
100 | |||
101 | expect(video.name).to.equal('test upload') | ||
102 | expect(video.support).to.equal('support_text') | ||
103 | expect(video.channel.name).to.equal('user_channel') | ||
35 | }) | 104 | }) |
36 | 105 | ||
37 | it('Should remember the authentifying material of the user', async function () { | 106 | it('Should import a video', async function () { |
38 | this.timeout(60000) | 107 | this.timeout(60000) |
39 | 108 | ||
40 | const env = getEnvCli(server) | 109 | const env = getEnvCli(server) |
41 | await execCLI(`${env} ` + cmd + ` auth add --url ${server.url} -U user_1 -p "super password"`) | 110 | |
111 | const params = `--target-url ${getYoutubeVideoUrl()} --channel-name user_channel` | ||
112 | |||
113 | await execCLI(`${env} ${cmd} import ${params}`) | ||
114 | }) | ||
115 | |||
116 | it('Should have imported the video', async function () { | ||
117 | this.timeout(60000) | ||
118 | |||
119 | await waitJobs([ server ]) | ||
120 | |||
121 | const res = await getVideosList(server.url) | ||
122 | |||
123 | expect(res.body.total).to.equal(2) | ||
124 | |||
125 | const videos: Video[] = res.body.data | ||
126 | const video = videos.find(v => v.name === 'small video - youtube') | ||
127 | expect(video).to.not.be.undefined | ||
128 | |||
129 | const videoDetails: VideoDetails = (await getVideo(server.url, video.id)).body | ||
130 | expect(videoDetails.channel.name).to.equal('user_channel') | ||
131 | expect(videoDetails.support).to.equal('super support text') | ||
132 | expect(videoDetails.nsfw).to.be.false | ||
133 | |||
134 | // So we can reimport it | ||
135 | await removeVideo(server.url, userAccessToken, video.id) | ||
136 | }) | ||
137 | |||
138 | it('Should import and override some imported attributes', async function () { | ||
139 | this.timeout(60000) | ||
140 | |||
141 | const env = getEnvCli(server) | ||
142 | |||
143 | const params = `--target-url ${getYoutubeVideoUrl()} --channel-name user_channel --video-name toto --nsfw --support support` | ||
144 | |||
145 | await execCLI(`${env} ${cmd} import ${params}`) | ||
146 | |||
147 | await waitJobs([ server ]) | ||
148 | |||
149 | { | ||
150 | const res = await getVideosList(server.url) | ||
151 | expect(res.body.total).to.equal(2) | ||
152 | |||
153 | const videos: Video[] = res.body.data | ||
154 | const video = videos.find(v => v.name === 'toto') | ||
155 | expect(video).to.not.be.undefined | ||
156 | |||
157 | const videoDetails: VideoDetails = (await getVideo(server.url, video.id)).body | ||
158 | expect(videoDetails.channel.name).to.equal('user_channel') | ||
159 | expect(videoDetails.support).to.equal('support') | ||
160 | expect(videoDetails.nsfw).to.be.true | ||
161 | expect(videoDetails.commentsEnabled).to.be.true | ||
162 | } | ||
163 | }) | ||
164 | |||
165 | it('Should remove the auth user', async function () { | ||
166 | const env = getEnvCli(server) | ||
167 | |||
168 | await execCLI(`${env} ${cmd} auth del ${server.url}`) | ||
169 | |||
170 | const stdout = await execCLI(`${env} ${cmd} --help`) | ||
171 | |||
172 | expect(stdout).to.contain('no instance selected') | ||
42 | }) | 173 | }) |
43 | 174 | ||
44 | after(async function () { | 175 | after(async function () { |
45 | this.timeout(10000) | 176 | this.timeout(10000) |
46 | 177 | ||
47 | await execCLI(cmd + ` auth del ${server.url}`) | ||
48 | |||
49 | await cleanupTests([ server ]) | 178 | await cleanupTests([ server ]) |
50 | }) | 179 | }) |
51 | }) | 180 | }) |
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' |
18 | import * as libxmljs from 'libxmljs' | 18 | import * as libxmljs from 'libxmljs' |
19 | import { addVideoCommentThread } from '../../../shared/extra-utils/videos/video-comments' | 19 | import { addVideoCommentThread } from '../../../shared/extra-utils/videos/video-comments' |
@@ -28,10 +28,10 @@ const expect = chai.expect | |||
28 | describe('Test syndication feeds', () => { | 28 | describe('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/cli.ts b/server/tools/cli.ts index 59e9fcfc4..2eec51aa4 100644 --- a/server/tools/cli.ts +++ b/server/tools/cli.ts | |||
@@ -1,5 +1,14 @@ | |||
1 | const config = require('application-config')('PeerTube/CLI') | 1 | import { Netrc } from 'netrc-parser' |
2 | const netrc = require('netrc-parser').default | 2 | import { getAppNumber, isTestInstance } from '../helpers/core-utils' |
3 | import { join } from 'path' | ||
4 | import { getVideoChannel, root } from '../../shared/extra-utils' | ||
5 | import { Command } from 'commander' | ||
6 | import { VideoChannel, VideoPrivacy } from '../../shared/models/videos' | ||
7 | |||
8 | let configName = 'PeerTube/CLI' | ||
9 | if (isTestInstance()) configName += `-${getAppNumber()}` | ||
10 | |||
11 | const config = require('application-config')(configName) | ||
3 | 12 | ||
4 | const version = require('../../../package.json').version | 13 | const version = require('../../../package.json').version |
5 | 14 | ||
@@ -12,7 +21,7 @@ function getSettings () { | |||
12 | return new Promise<Settings>((res, rej) => { | 21 | return new Promise<Settings>((res, rej) => { |
13 | const defaultSettings = { | 22 | const defaultSettings = { |
14 | remotes: [], | 23 | remotes: [], |
15 | default: 0 | 24 | default: -1 |
16 | } | 25 | } |
17 | 26 | ||
18 | config.read((err, data) => { | 27 | config.read((err, data) => { |
@@ -24,6 +33,12 @@ function getSettings () { | |||
24 | } | 33 | } |
25 | 34 | ||
26 | async function getNetrc () { | 35 | async function getNetrc () { |
36 | const Netrc = require('netrc-parser').Netrc | ||
37 | |||
38 | const netrc = isTestInstance() | ||
39 | ? new Netrc(join(root(), 'test' + getAppNumber(), 'netrc')) | ||
40 | : new Netrc() | ||
41 | |||
27 | await netrc.load() | 42 | await netrc.load() |
28 | 43 | ||
29 | return netrc | 44 | return netrc |
@@ -31,7 +46,17 @@ async function getNetrc () { | |||
31 | 46 | ||
32 | function writeSettings (settings) { | 47 | function writeSettings (settings) { |
33 | return new Promise((res, rej) => { | 48 | return new Promise((res, rej) => { |
34 | config.write(settings, function (err) { | 49 | config.write(settings, err => { |
50 | if (err) return rej(err) | ||
51 | |||
52 | return res() | ||
53 | }) | ||
54 | }) | ||
55 | } | ||
56 | |||
57 | function deleteSettings () { | ||
58 | return new Promise((res, rej) => { | ||
59 | config.trash((err) => { | ||
35 | if (err) return rej(err) | 60 | if (err) return rej(err) |
36 | 61 | ||
37 | return res() | 62 | return res() |
@@ -39,10 +64,10 @@ function writeSettings (settings) { | |||
39 | }) | 64 | }) |
40 | } | 65 | } |
41 | 66 | ||
42 | function getRemoteObjectOrDie (program: any, settings: Settings) { | 67 | function getRemoteObjectOrDie (program: any, settings: Settings, netrc: Netrc) { |
43 | if (!program['url'] || !program['username'] || !program['password']) { | 68 | if (!program['url'] || !program['username'] || !program['password']) { |
44 | // No remote and we don't have program parameters: throw | 69 | // No remote and we don't have program parameters: quit |
45 | if (settings.remotes.length === 0) { | 70 | if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) { |
46 | if (!program[ 'url' ]) console.error('--url field is required.') | 71 | if (!program[ 'url' ]) console.error('--url field is required.') |
47 | if (!program[ 'username' ]) console.error('--username field is required.') | 72 | if (!program[ 'username' ]) console.error('--username field is required.') |
48 | if (!program[ 'password' ]) console.error('--password field is required.') | 73 | if (!program[ 'password' ]) console.error('--password field is required.') |
@@ -54,14 +79,12 @@ function getRemoteObjectOrDie (program: any, settings: Settings) { | |||
54 | let username: string = program['username'] | 79 | let username: string = program['username'] |
55 | let password: string = program['password'] | 80 | let password: string = program['password'] |
56 | 81 | ||
57 | if (!url) { | 82 | if (!url && settings.default !== -1) url = settings.remotes[settings.default] |
58 | url = settings.default !== -1 | 83 | |
59 | ? settings.remotes[settings.default] | 84 | const machine = netrc.machines[url] |
60 | : settings.remotes[0] | ||
61 | } | ||
62 | 85 | ||
63 | if (!username) username = netrc.machines[url].login | 86 | if (!username && machine) username = machine.login |
64 | if (!password) password = netrc.machines[url].password | 87 | if (!password && machine) password = machine.password |
65 | 88 | ||
66 | return { url, username, password } | 89 | return { url, username, password } |
67 | } | 90 | } |
@@ -73,6 +96,71 @@ function getRemoteObjectOrDie (program: any, settings: Settings) { | |||
73 | } | 96 | } |
74 | } | 97 | } |
75 | 98 | ||
99 | function buildCommonVideoOptions (command: Command) { | ||
100 | function list (val) { | ||
101 | return val.split(',') | ||
102 | } | ||
103 | |||
104 | return command | ||
105 | .option('-n, --video-name <name>', 'Video name') | ||
106 | .option('-c, --category <category_number>', 'Category number') | ||
107 | .option('-l, --licence <licence_number>', 'Licence number') | ||
108 | .option('-L, --language <language_code>', 'Language ISO 639 code (fr or en...)') | ||
109 | .option('-t, --tags <tags>', 'Video tags', list) | ||
110 | .option('-N, --nsfw', 'Video is Not Safe For Work') | ||
111 | .option('-d, --video-description <description>', 'Video description') | ||
112 | .option('-P, --privacy <privacy_number>', 'Privacy') | ||
113 | .option('-C, --channel-name <channel_name>', 'Channel name') | ||
114 | .option('-m, --comments-enabled', 'Enable comments') | ||
115 | .option('-s, --support <support>', 'Video support text') | ||
116 | .option('-w, --wait-transcoding', 'Wait transcoding before publishing the video') | ||
117 | } | ||
118 | |||
119 | async function buildVideoAttributesFromCommander (url: string, command: Command, defaultAttributes: any) { | ||
120 | const defaultBooleanAttributes = { | ||
121 | nsfw: false, | ||
122 | commentsEnabled: true, | ||
123 | downloadEnabled: true, | ||
124 | waitTranscoding: true | ||
125 | } | ||
126 | |||
127 | const booleanAttributes: { [id in keyof typeof defaultBooleanAttributes]: boolean } | {} = {} | ||
128 | |||
129 | for (const key of Object.keys(defaultBooleanAttributes)) { | ||
130 | if (command[ key ] !== undefined) { | ||
131 | booleanAttributes[key] = command[ key ] | ||
132 | } else if (defaultAttributes[key] !== undefined) { | ||
133 | booleanAttributes[key] = defaultAttributes[key] | ||
134 | } else { | ||
135 | booleanAttributes[key] = defaultBooleanAttributes[key] | ||
136 | } | ||
137 | } | ||
138 | |||
139 | const videoAttributes = { | ||
140 | name: command[ 'videoName' ] || defaultAttributes.name, | ||
141 | category: command[ 'category' ] || defaultAttributes.category || undefined, | ||
142 | licence: command[ 'licence' ] || defaultAttributes.licence || undefined, | ||
143 | language: command[ 'language' ] || defaultAttributes.language || undefined, | ||
144 | privacy: command[ 'privacy' ] || defaultAttributes.privacy || VideoPrivacy.PUBLIC, | ||
145 | support: command[ 'support' ] || defaultAttributes.support || undefined | ||
146 | } | ||
147 | |||
148 | Object.assign(videoAttributes, booleanAttributes) | ||
149 | |||
150 | if (command[ 'channelName' ]) { | ||
151 | const res = await getVideoChannel(url, command['channelName']) | ||
152 | const videoChannel: VideoChannel = res.body | ||
153 | |||
154 | Object.assign(videoAttributes, { channelId: videoChannel.id }) | ||
155 | |||
156 | if (!videoAttributes.support && videoChannel.support) { | ||
157 | Object.assign(videoAttributes, { support: videoChannel.support }) | ||
158 | } | ||
159 | } | ||
160 | |||
161 | return videoAttributes | ||
162 | } | ||
163 | |||
76 | // --------------------------------------------------------------------------- | 164 | // --------------------------------------------------------------------------- |
77 | 165 | ||
78 | export { | 166 | export { |
@@ -81,5 +169,9 @@ export { | |||
81 | getSettings, | 169 | getSettings, |
82 | getNetrc, | 170 | getNetrc, |
83 | getRemoteObjectOrDie, | 171 | getRemoteObjectOrDie, |
84 | writeSettings | 172 | writeSettings, |
173 | deleteSettings, | ||
174 | |||
175 | buildCommonVideoOptions, | ||
176 | buildVideoAttributesFromCommander | ||
85 | } | 177 | } |
diff --git a/server/tools/package.json b/server/tools/package.json new file mode 100644 index 000000000..22fb8d24c --- /dev/null +++ b/server/tools/package.json | |||
@@ -0,0 +1,14 @@ | |||
1 | { | ||
2 | "name": "@peertube/cli", | ||
3 | "version": "1.0.0", | ||
4 | "private": true, | ||
5 | "dependencies": { | ||
6 | "application-config": "^1.0.1", | ||
7 | "cli-table": "^0.3.1", | ||
8 | "netrc-parser": "^3.1.6", | ||
9 | "webtorrent-hybrid": "^2.1.0" | ||
10 | }, | ||
11 | "summon": { | ||
12 | "silent": true | ||
13 | } | ||
14 | } | ||
diff --git a/server/tools/peertube-auth.ts b/server/tools/peertube-auth.ts index 8bc3d332c..ff5ffb60e 100644 --- a/server/tools/peertube-auth.ts +++ b/server/tools/peertube-auth.ts | |||
@@ -9,7 +9,11 @@ const Table = require('cli-table') | |||
9 | async function delInstance (url: string) { | 9 | async function delInstance (url: string) { |
10 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) | 10 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) |
11 | 11 | ||
12 | settings.remotes.splice(settings.remotes.indexOf(url)) | 12 | const index = settings.remotes.indexOf(url) |
13 | settings.remotes.splice(index) | ||
14 | |||
15 | if (settings.default === index) settings.default = -1 | ||
16 | |||
13 | await writeSettings(settings) | 17 | await writeSettings(settings) |
14 | 18 | ||
15 | delete netrc.machines[url] | 19 | delete netrc.machines[url] |
@@ -17,12 +21,17 @@ async function delInstance (url: string) { | |||
17 | await netrc.save() | 21 | await netrc.save() |
18 | } | 22 | } |
19 | 23 | ||
20 | async function setInstance (url: string, username: string, password: string) { | 24 | async function setInstance (url: string, username: string, password: string, isDefault: boolean) { |
21 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) | 25 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) |
22 | 26 | ||
23 | if (settings.remotes.indexOf(url) === -1) { | 27 | if (settings.remotes.indexOf(url) === -1) { |
24 | settings.remotes.push(url) | 28 | settings.remotes.push(url) |
25 | } | 29 | } |
30 | |||
31 | if (isDefault || settings.remotes.length === 1) { | ||
32 | settings.default = settings.remotes.length - 1 | ||
33 | } | ||
34 | |||
26 | await writeSettings(settings) | 35 | await writeSettings(settings) |
27 | 36 | ||
28 | netrc.machines[url] = { login: username, password } | 37 | netrc.machines[url] = { login: username, password } |
@@ -66,7 +75,7 @@ program | |||
66 | } | 75 | } |
67 | } | 76 | } |
68 | }, async (_, result) => { | 77 | }, async (_, result) => { |
69 | await setInstance(result.url, result.username, result.password) | 78 | await setInstance(result.url, result.username, result.password, program['default']) |
70 | 79 | ||
71 | process.exit(0) | 80 | process.exit(0) |
72 | }) | 81 | }) |
@@ -93,6 +102,8 @@ program | |||
93 | }) | 102 | }) |
94 | 103 | ||
95 | settings.remotes.forEach(element => { | 104 | settings.remotes.forEach(element => { |
105 | if (!netrc.machines[element]) return | ||
106 | |||
96 | table.push([ | 107 | table.push([ |
97 | element, | 108 | element, |
98 | netrc.machines[element].login | 109 | netrc.machines[element].login |
diff --git a/server/tools/peertube-get-access-token.ts b/server/tools/peertube-get-access-token.ts index 85660de2c..103495347 100644 --- a/server/tools/peertube-get-access-token.ts +++ b/server/tools/peertube-get-access-token.ts | |||
@@ -1,12 +1,5 @@ | |||
1 | import * as program from 'commander' | 1 | import * as program from 'commander' |
2 | 2 | import { getClient, Server, serverLogin } from '../../shared/extra-utils' | |
3 | import { | ||
4 | getClient, | ||
5 | serverLogin, | ||
6 | Server, | ||
7 | Client, | ||
8 | User | ||
9 | } from '../../shared/extra-utils' | ||
10 | 3 | ||
11 | program | 4 | program |
12 | .option('-u, --url <url>', 'Server url') | 5 | .option('-u, --url <url>', 'Server url') |
@@ -22,6 +15,7 @@ if ( | |||
22 | if (!program['url']) console.error('--url field is required.') | 15 | if (!program['url']) console.error('--url field is required.') |
23 | if (!program['username']) console.error('--username field is required.') | 16 | if (!program['username']) console.error('--username field is required.') |
24 | if (!program['password']) console.error('--password field is required.') | 17 | if (!program['password']) console.error('--password field is required.') |
18 | |||
25 | process.exit(-1) | 19 | process.exit(-1) |
26 | } | 20 | } |
27 | 21 | ||
@@ -32,11 +26,11 @@ getClient(program.url) | |||
32 | user: { | 26 | user: { |
33 | username: program['username'], | 27 | username: program['username'], |
34 | password: program['password'] | 28 | password: program['password'] |
35 | } as User, | 29 | }, |
36 | client: { | 30 | client: { |
37 | id: res.body.client_id as string, | 31 | id: res.body.client_id, |
38 | secret: res.body.client_secret as string | 32 | secret: res.body.client_secret |
39 | } as Client | 33 | } |
40 | } as Server | 34 | } as Server |
41 | 35 | ||
42 | return serverLogin(server) | 36 | return serverLogin(server) |
diff --git a/server/tools/peertube-import-videos.ts b/server/tools/peertube-import-videos.ts index 9a366dbbd..d7bb00e02 100644 --- a/server/tools/peertube-import-videos.ts +++ b/server/tools/peertube-import-videos.ts | |||
@@ -3,7 +3,6 @@ require('tls').DEFAULT_ECDH_CURVE = 'auto' | |||
3 | 3 | ||
4 | import * as program from 'commander' | 4 | import * as program from 'commander' |
5 | import { join } from 'path' | 5 | import { join } from 'path' |
6 | import { VideoPrivacy } from '../../shared/models/videos' | ||
7 | import { doRequestAndSaveToFile } from '../helpers/requests' | 6 | import { doRequestAndSaveToFile } from '../helpers/requests' |
8 | import { CONSTRAINTS_FIELDS } from '../initializers/constants' | 7 | import { CONSTRAINTS_FIELDS } from '../initializers/constants' |
9 | import { getClient, getVideoCategories, login, searchVideoWithSort, uploadVideo } from '../../shared/extra-utils/index' | 8 | import { getClient, getVideoCategories, login, searchVideoWithSort, uploadVideo } from '../../shared/extra-utils/index' |
@@ -12,29 +11,34 @@ import * as prompt from 'prompt' | |||
12 | import { remove } from 'fs-extra' | 11 | import { remove } from 'fs-extra' |
13 | import { sha256 } from '../helpers/core-utils' | 12 | import { sha256 } from '../helpers/core-utils' |
14 | import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl' | 13 | import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl' |
15 | import { getNetrc, getRemoteObjectOrDie, getSettings } from './cli' | 14 | import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getNetrc, getRemoteObjectOrDie, getSettings } from './cli' |
16 | 15 | ||
17 | let accessToken: string | 16 | type UserInfo = { |
18 | let client: { id: string, secret: string } | 17 | username: string |
18 | password: string | ||
19 | } | ||
19 | 20 | ||
20 | const processOptions = { | 21 | const processOptions = { |
21 | cwd: __dirname, | 22 | cwd: __dirname, |
22 | maxBuffer: Infinity | 23 | maxBuffer: Infinity |
23 | } | 24 | } |
24 | 25 | ||
25 | program | 26 | let command = program |
26 | .name('import-videos') | 27 | .name('import-videos') |
28 | |||
29 | command = buildCommonVideoOptions(command) | ||
30 | |||
31 | command | ||
27 | .option('-u, --url <url>', 'Server url') | 32 | .option('-u, --url <url>', 'Server url') |
28 | .option('-U, --username <username>', 'Username') | 33 | .option('-U, --username <username>', 'Username') |
29 | .option('-p, --password <token>', 'Password') | 34 | .option('-p, --password <token>', 'Password') |
30 | .option('-t, --target-url <targetUrl>', 'Video target URL') | 35 | .option('-t, --target-url <targetUrl>', 'Video target URL') |
31 | .option('-l, --language <languageCode>', 'Language ISO 639 code (fr or en...)') | ||
32 | .option('-v, --verbose', 'Verbose mode') | 36 | .option('-v, --verbose', 'Verbose mode') |
33 | .parse(process.argv) | 37 | .parse(process.argv) |
34 | 38 | ||
35 | Promise.all([ getSettings(), getNetrc() ]) | 39 | Promise.all([ getSettings(), getNetrc() ]) |
36 | .then(([ settings, netrc ]) => { | 40 | .then(([ settings, netrc ]) => { |
37 | const { url, username, password } = getRemoteObjectOrDie(program, settings) | 41 | const { url, username, password } = getRemoteObjectOrDie(program, settings, netrc) |
38 | 42 | ||
39 | if (!program[ 'targetUrl' ]) { | 43 | if (!program[ 'targetUrl' ]) { |
40 | console.error('--targetUrl field is required.') | 44 | console.error('--targetUrl field is required.') |
@@ -45,56 +49,20 @@ Promise.all([ getSettings(), getNetrc() ]) | |||
45 | removeEndSlashes(url) | 49 | removeEndSlashes(url) |
46 | removeEndSlashes(program[ 'targetUrl' ]) | 50 | removeEndSlashes(program[ 'targetUrl' ]) |
47 | 51 | ||
48 | const user = { | 52 | const user = { username, password } |
49 | username: username, | ||
50 | password: password | ||
51 | } | ||
52 | 53 | ||
53 | run(user, url) | 54 | run(url, user) |
54 | .catch(err => { | 55 | .catch(err => { |
55 | console.error(err) | 56 | console.error(err) |
56 | process.exit(-1) | 57 | process.exit(-1) |
57 | }) | 58 | }) |
58 | }) | 59 | }) |
59 | 60 | ||
60 | async function promptPassword () { | 61 | async function run (url: string, user: UserInfo) { |
61 | return new Promise((res, rej) => { | ||
62 | prompt.start() | ||
63 | const schema = { | ||
64 | properties: { | ||
65 | password: { | ||
66 | hidden: true, | ||
67 | required: true | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | prompt.get(schema, function (err, result) { | ||
72 | if (err) { | ||
73 | return rej(err) | ||
74 | } | ||
75 | return res(result.password) | ||
76 | }) | ||
77 | }) | ||
78 | } | ||
79 | |||
80 | async function run (user, url: string) { | ||
81 | if (!user.password) { | 62 | if (!user.password) { |
82 | user.password = await promptPassword() | 63 | user.password = await promptPassword() |
83 | } | 64 | } |
84 | 65 | ||
85 | const res = await getClient(url) | ||
86 | client = { | ||
87 | id: res.body.client_id, | ||
88 | secret: res.body.client_secret | ||
89 | } | ||
90 | |||
91 | try { | ||
92 | const res = await login(program[ 'url' ], client, user) | ||
93 | accessToken = res.body.access_token | ||
94 | } catch (err) { | ||
95 | throw new Error('Cannot authenticate. Please check your username/password.') | ||
96 | } | ||
97 | |||
98 | const youtubeDL = await safeGetYoutubeDL() | 66 | const youtubeDL = await safeGetYoutubeDL() |
99 | 67 | ||
100 | const options = [ '-j', '--flat-playlist', '--playlist-reverse' ] | 68 | const options = [ '-j', '--flat-playlist', '--playlist-reverse' ] |
@@ -115,7 +83,12 @@ async function run (user, url: string) { | |||
115 | console.log('Will download and upload %d videos.\n', infoArray.length) | 83 | console.log('Will download and upload %d videos.\n', infoArray.length) |
116 | 84 | ||
117 | for (const info of infoArray) { | 85 | for (const info of infoArray) { |
118 | await processVideo(info, program[ 'language' ], processOptions.cwd, url, user) | 86 | await processVideo({ |
87 | cwd: processOptions.cwd, | ||
88 | url, | ||
89 | user, | ||
90 | youtubeInfo: info | ||
91 | }) | ||
119 | } | 92 | } |
120 | 93 | ||
121 | console.log('Video/s for user %s imported: %s', program[ 'username' ], program[ 'targetUrl' ]) | 94 | console.log('Video/s for user %s imported: %s', program[ 'username' ], program[ 'targetUrl' ]) |
@@ -123,11 +96,18 @@ async function run (user, url: string) { | |||
123 | }) | 96 | }) |
124 | } | 97 | } |
125 | 98 | ||
126 | function processVideo (info: any, languageCode: string, cwd: string, url: string, user) { | 99 | function processVideo (parameters: { |
100 | cwd: string, | ||
101 | url: string, | ||
102 | user: { username: string, password: string }, | ||
103 | youtubeInfo: any | ||
104 | }) { | ||
105 | const { youtubeInfo, cwd, url, user } = parameters | ||
106 | |||
127 | return new Promise(async res => { | 107 | return new Promise(async res => { |
128 | if (program[ 'verbose' ]) console.log('Fetching object.', info) | 108 | if (program[ 'verbose' ]) console.log('Fetching object.', youtubeInfo) |
129 | 109 | ||
130 | const videoInfo = await fetchObject(info) | 110 | const videoInfo = await fetchObject(youtubeInfo) |
131 | if (program[ 'verbose' ]) console.log('Fetched object.', videoInfo) | 111 | if (program[ 'verbose' ]) console.log('Fetched object.', videoInfo) |
132 | 112 | ||
133 | const result = await searchVideoWithSort(url, videoInfo.title, '-match') | 113 | const result = await searchVideoWithSort(url, videoInfo.title, '-match') |
@@ -153,7 +133,13 @@ function processVideo (info: any, languageCode: string, cwd: string, url: string | |||
153 | } | 133 | } |
154 | 134 | ||
155 | console.log(output.join('\n')) | 135 | console.log(output.join('\n')) |
156 | await uploadVideoOnPeerTube(normalizeObject(videoInfo), path, cwd, url, user, languageCode) | 136 | await uploadVideoOnPeerTube({ |
137 | cwd, | ||
138 | url, | ||
139 | user, | ||
140 | videoInfo: normalizeObject(videoInfo), | ||
141 | videoPath: path | ||
142 | }) | ||
157 | return res() | 143 | return res() |
158 | }) | 144 | }) |
159 | } catch (err) { | 145 | } catch (err) { |
@@ -163,7 +149,15 @@ function processVideo (info: any, languageCode: string, cwd: string, url: string | |||
163 | }) | 149 | }) |
164 | } | 150 | } |
165 | 151 | ||
166 | async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: string, url: string, user, language?: string) { | 152 | async function uploadVideoOnPeerTube (parameters: { |
153 | videoInfo: any, | ||
154 | videoPath: string, | ||
155 | cwd: string, | ||
156 | url: string, | ||
157 | user: { username: string; password: string } | ||
158 | }) { | ||
159 | const { videoInfo, videoPath, cwd, url, user } = parameters | ||
160 | |||
167 | const category = await getCategory(videoInfo.categories, url) | 161 | const category = await getCategory(videoInfo.categories, url) |
168 | const licence = getLicence(videoInfo.license) | 162 | const licence = getLicence(videoInfo.license) |
169 | let tags = [] | 163 | let tags = [] |
@@ -186,7 +180,7 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: st | |||
186 | 180 | ||
187 | const originallyPublishedAt = buildOriginallyPublishedAt(videoInfo) | 181 | const originallyPublishedAt = buildOriginallyPublishedAt(videoInfo) |
188 | 182 | ||
189 | const videoAttributes = { | 183 | const defaultAttributes = { |
190 | name: truncate(videoInfo.title, { | 184 | name: truncate(videoInfo.title, { |
191 | 'length': CONSTRAINTS_FIELDS.VIDEOS.NAME.max, | 185 | 'length': CONSTRAINTS_FIELDS.VIDEOS.NAME.max, |
192 | 'separator': /,? +/, | 186 | 'separator': /,? +/, |
@@ -194,30 +188,31 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: st | |||
194 | }), | 188 | }), |
195 | category, | 189 | category, |
196 | licence, | 190 | licence, |
197 | language, | ||
198 | nsfw: isNSFW(videoInfo), | 191 | nsfw: isNSFW(videoInfo), |
199 | waitTranscoding: true, | 192 | description: videoInfo.description, |
200 | commentsEnabled: true, | 193 | tags |
201 | downloadEnabled: true, | 194 | } |
202 | description: videoInfo.description || undefined, | 195 | |
203 | support: undefined, | 196 | const videoAttributes = await buildVideoAttributesFromCommander(url, program, defaultAttributes) |
204 | tags, | 197 | |
205 | privacy: VideoPrivacy.PUBLIC, | 198 | Object.assign(videoAttributes, { |
206 | fixture: videoPath, | 199 | originallyPublishedAt: originallyPublishedAt ? originallyPublishedAt.toISOString() : null, |
207 | thumbnailfile, | 200 | thumbnailfile, |
208 | previewfile: thumbnailfile, | 201 | previewfile: thumbnailfile, |
209 | originallyPublishedAt: originallyPublishedAt ? originallyPublishedAt.toISOString() : null | 202 | fixture: videoPath |
210 | } | 203 | }) |
211 | 204 | ||
212 | console.log('\nUploading on PeerTube video "%s".', videoAttributes.name) | 205 | console.log('\nUploading on PeerTube video "%s".', videoAttributes.name) |
206 | |||
207 | let accessToken = await getAccessTokenOrDie(url, user) | ||
208 | |||
213 | try { | 209 | try { |
214 | await uploadVideo(url, accessToken, videoAttributes) | 210 | await uploadVideo(url, accessToken, videoAttributes) |
215 | } catch (err) { | 211 | } catch (err) { |
216 | if (err.message.indexOf('401') !== -1) { | 212 | if (err.message.indexOf('401') !== -1) { |
217 | console.log('Got 401 Unauthorized, token may have expired, renewing token and retry.') | 213 | console.log('Got 401 Unauthorized, token may have expired, renewing token and retry.') |
218 | 214 | ||
219 | const res = await login(url, client, user) | 215 | accessToken = await getAccessTokenOrDie(url, user) |
220 | accessToken = res.body.access_token | ||
221 | 216 | ||
222 | await uploadVideo(url, accessToken, videoAttributes) | 217 | await uploadVideo(url, accessToken, videoAttributes) |
223 | } else { | 218 | } else { |
@@ -232,6 +227,8 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string, cwd: st | |||
232 | console.log('Uploaded video "%s"!\n', videoAttributes.name) | 227 | console.log('Uploaded video "%s"!\n', videoAttributes.name) |
233 | } | 228 | } |
234 | 229 | ||
230 | /* ---------------------------------------------------------- */ | ||
231 | |||
235 | async function getCategory (categories: string[], url: string) { | 232 | async function getCategory (categories: string[], url: string) { |
236 | if (!categories) return undefined | 233 | if (!categories) return undefined |
237 | 234 | ||
@@ -250,8 +247,6 @@ async function getCategory (categories: string[], url: string) { | |||
250 | return undefined | 247 | return undefined |
251 | } | 248 | } |
252 | 249 | ||
253 | /* ---------------------------------------------------------- */ | ||
254 | |||
255 | function getLicence (licence: string) { | 250 | function getLicence (licence: string) { |
256 | if (!licence) return undefined | 251 | if (!licence) return undefined |
257 | 252 | ||
@@ -305,9 +300,7 @@ function buildUrl (info: any) { | |||
305 | } | 300 | } |
306 | 301 | ||
307 | function isNSFW (info: any) { | 302 | function isNSFW (info: any) { |
308 | if (info.age_limit && info.age_limit >= 16) return true | 303 | return info.age_limit && info.age_limit >= 16 |
309 | |||
310 | return false | ||
311 | } | 304 | } |
312 | 305 | ||
313 | function removeEndSlashes (url: string) { | 306 | function removeEndSlashes (url: string) { |
@@ -315,3 +308,39 @@ function removeEndSlashes (url: string) { | |||
315 | url.slice(0, -1) | 308 | url.slice(0, -1) |
316 | } | 309 | } |
317 | } | 310 | } |
311 | |||
312 | async function promptPassword () { | ||
313 | return new Promise<string>((res, rej) => { | ||
314 | prompt.start() | ||
315 | const schema = { | ||
316 | properties: { | ||
317 | password: { | ||
318 | hidden: true, | ||
319 | required: true | ||
320 | } | ||
321 | } | ||
322 | } | ||
323 | prompt.get(schema, function (err, result) { | ||
324 | if (err) { | ||
325 | return rej(err) | ||
326 | } | ||
327 | return res(result.password) | ||
328 | }) | ||
329 | }) | ||
330 | } | ||
331 | |||
332 | async function getAccessTokenOrDie (url: string, user: UserInfo) { | ||
333 | const resClient = await getClient(url) | ||
334 | const client = { | ||
335 | id: resClient.body.client_id, | ||
336 | secret: resClient.body.client_secret | ||
337 | } | ||
338 | |||
339 | try { | ||
340 | const res = await login(url, client, user) | ||
341 | return res.body.access_token | ||
342 | } catch (err) { | ||
343 | console.error('Cannot authenticate. Please check your username/password.') | ||
344 | process.exit(-1) | ||
345 | } | ||
346 | } | ||
diff --git a/server/tools/peertube-repl.ts b/server/tools/peertube-repl.ts index 04d8b95a3..fbdec1613 100644 --- a/server/tools/peertube-repl.ts +++ b/server/tools/peertube-repl.ts | |||
@@ -43,7 +43,7 @@ const start = async () => { | |||
43 | Object.defineProperty(context, prop, { | 43 | Object.defineProperty(context, prop, { |
44 | configurable: false, | 44 | configurable: false, |
45 | enumerable: true, | 45 | enumerable: true, |
46 | value: properties[prop] | 46 | value: properties[ prop ] |
47 | }) | 47 | }) |
48 | } | 48 | } |
49 | } | 49 | } |
@@ -69,8 +69,7 @@ const start = async () => { | |||
69 | 69 | ||
70 | } | 70 | } |
71 | 71 | ||
72 | start().then((data) => { | 72 | start() |
73 | // do nothing | 73 | .catch((err) => { |
74 | }).catch((err) => { | 74 | console.error(err) |
75 | console.error(err) | 75 | }) |
76 | }) | ||
diff --git a/server/tools/peertube-upload.ts b/server/tools/peertube-upload.ts index 687f2e60b..c00205e8f 100644 --- a/server/tools/peertube-upload.ts +++ b/server/tools/peertube-upload.ts | |||
@@ -3,54 +3,47 @@ import { access, constants } from 'fs-extra' | |||
3 | import { isAbsolute } from 'path' | 3 | import { isAbsolute } from 'path' |
4 | import { getClient, login } from '../../shared/extra-utils' | 4 | import { getClient, login } from '../../shared/extra-utils' |
5 | import { uploadVideo } from '../../shared/extra-utils/' | 5 | import { uploadVideo } from '../../shared/extra-utils/' |
6 | import { VideoPrivacy } from '../../shared/models/videos' | 6 | import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getNetrc, getRemoteObjectOrDie, getSettings } from './cli' |
7 | import { getRemoteObjectOrDie, getSettings } from './cli' | ||
8 | 7 | ||
9 | program | 8 | let command = program |
10 | .name('upload') | 9 | .name('upload') |
10 | |||
11 | command = buildCommonVideoOptions(command) | ||
12 | |||
13 | command | ||
14 | |||
11 | .option('-u, --url <url>', 'Server url') | 15 | .option('-u, --url <url>', 'Server url') |
12 | .option('-U, --username <username>', 'Username') | 16 | .option('-U, --username <username>', 'Username') |
13 | .option('-p, --password <token>', 'Password') | 17 | .option('-p, --password <token>', 'Password') |
14 | .option('-n, --video-name <name>', 'Video name') | ||
15 | .option('-P, --privacy <privacy_number>', 'Privacy') | ||
16 | .option('-N, --nsfw', 'Video is Not Safe For Work') | ||
17 | .option('-c, --category <category_number>', 'Category number') | ||
18 | .option('-C, --channel-id <channel_id>', 'Channel ID') | ||
19 | .option('-m, --comments-enabled', 'Enable comments') | ||
20 | .option('-l, --licence <licence_number>', 'Licence number') | ||
21 | .option('-L, --language <language_code>', 'Language ISO 639 code (fr or en...)') | ||
22 | .option('-d, --video-description <description>', 'Video description') | ||
23 | .option('-t, --tags <tags>', 'Video tags', list) | ||
24 | .option('-b, --thumbnail <thumbnailPath>', 'Thumbnail path') | 18 | .option('-b, --thumbnail <thumbnailPath>', 'Thumbnail path') |
25 | .option('-v, --preview <previewPath>', 'Preview path') | 19 | .option('-v, --preview <previewPath>', 'Preview path') |
26 | .option('-f, --file <file>', 'Video absolute file path') | 20 | .option('-f, --file <file>', 'Video absolute file path') |
27 | .parse(process.argv) | 21 | .parse(process.argv) |
28 | 22 | ||
29 | getSettings() | 23 | Promise.all([ getSettings(), getNetrc() ]) |
30 | .then(settings => { | 24 | .then(([ settings, netrc ]) => { |
31 | const { url, username, password } = getRemoteObjectOrDie(program, settings) | 25 | const { url, username, password } = getRemoteObjectOrDie(program, settings, netrc) |
32 | 26 | ||
33 | if (!program['videoName'] || !program['file'] || !program['channelId']) { | 27 | if (!program[ 'videoName' ] || !program[ 'file' ]) { |
34 | if (!program['videoName']) console.error('--video-name is required.') | 28 | if (!program[ 'videoName' ]) console.error('--video-name is required.') |
35 | if (!program['file']) console.error('--file is required.') | 29 | if (!program[ 'file' ]) console.error('--file is required.') |
36 | if (!program['channelId']) console.error('--channel-id is required.') | ||
37 | 30 | ||
38 | process.exit(-1) | 31 | process.exit(-1) |
39 | } | 32 | } |
40 | 33 | ||
41 | if (isAbsolute(program['file']) === false) { | 34 | if (isAbsolute(program[ 'file' ]) === false) { |
42 | console.error('File path should be absolute.') | 35 | console.error('File path should be absolute.') |
43 | process.exit(-1) | 36 | process.exit(-1) |
44 | } | 37 | } |
45 | 38 | ||
46 | run(url, username, password).catch(err => { | 39 | run(url, username, password).catch(err => { |
47 | console.error(err) | 40 | console.error(err) |
48 | process.exit(-1) | 41 | process.exit(-1) |
49 | }) | 42 | }) |
50 | }) | 43 | }) |
51 | 44 | ||
52 | async function run (url: string, username: string, password: string) { | 45 | async function run (url: string, username: string, password: string) { |
53 | const resClient = await getClient(program[ 'url' ]) | 46 | const resClient = await getClient(url) |
54 | const client = { | 47 | const client = { |
55 | id: resClient.body.client_id, | 48 | id: resClient.body.client_id, |
56 | secret: resClient.body.client_secret | 49 | secret: resClient.body.client_secret |
@@ -70,38 +63,26 @@ async function run (url: string, username: string, password: string) { | |||
70 | 63 | ||
71 | console.log('Uploading %s video...', program[ 'videoName' ]) | 64 | console.log('Uploading %s video...', program[ 'videoName' ]) |
72 | 65 | ||
73 | const videoAttributes = { | 66 | const defaultAttributes = { |
74 | name: program['videoName'], | 67 | tags: command[ 'tags' ], |
75 | category: program['category'] || undefined, | 68 | description: command[ 'videoDescription' ] |
76 | channelId: program['channelId'], | ||
77 | licence: program['licence'] || undefined, | ||
78 | language: program['language'] || undefined, | ||
79 | nsfw: program['nsfw'] !== undefined ? program['nsfw'] : false, | ||
80 | description: program['videoDescription'] || '', | ||
81 | tags: program['tags'] || [], | ||
82 | commentsEnabled: program['commentsEnabled'] !== undefined ? program['commentsEnabled'] : true, | ||
83 | downloadEnabled: program['downloadEnabled'] !== undefined ? program['downloadEnabled'] : true, | ||
84 | fixture: program['file'], | ||
85 | thumbnailfile: program['thumbnail'], | ||
86 | previewfile: program['preview'], | ||
87 | waitTranscoding: true, | ||
88 | privacy: program['privacy'] || VideoPrivacy.PUBLIC, | ||
89 | support: undefined | ||
90 | } | 69 | } |
70 | const videoAttributes = await buildVideoAttributesFromCommander(url, program, defaultAttributes) | ||
71 | |||
72 | Object.assign(videoAttributes, { | ||
73 | fixture: program[ 'file' ], | ||
74 | thumbnailfile: program[ 'thumbnail' ], | ||
75 | previewfile: program[ 'preview' ] | ||
76 | }) | ||
91 | 77 | ||
92 | try { | 78 | try { |
93 | await uploadVideo(url, accessToken, videoAttributes) | 79 | await uploadVideo(url, accessToken, videoAttributes) |
94 | console.log(`Video ${program['videoName']} uploaded.`) | 80 | console.log(`Video ${program[ 'videoName' ]} uploaded.`) |
95 | process.exit(0) | 81 | process.exit(0) |
96 | } catch (err) { | 82 | } catch (err) { |
97 | console.log('coucou') | ||
98 | console.error(require('util').inspect(err)) | 83 | console.error(require('util').inspect(err)) |
99 | process.exit(-1) | 84 | process.exit(-1) |
100 | } | 85 | } |
101 | } | 86 | } |
102 | 87 | ||
103 | // ---------------------------------------------------------------------------- | 88 | // ---------------------------------------------------------------------------- |
104 | |||
105 | function list (val) { | ||
106 | return val.split(',') | ||
107 | } | ||
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 @@ | |||
1 | import * as program from 'commander' | 1 | import * as program from 'commander' |
2 | import * as summon from 'summon-install' | ||
3 | import { join } from 'path' | 2 | import { join } from 'path' |
4 | import { execSync } from 'child_process' | 3 | import { execSync } from 'child_process' |
5 | import { root } from '../helpers/core-utils' | ||
6 | |||
7 | let videoURL | ||
8 | 4 | ||
9 | program | 5 | program |
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 | ||
41 | if (!videoURL) { | 38 | async 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 | ||
46 | handler(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 | ||
48 | function 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..daa5586c3 100755..100644 --- a/server/tools/peertube.ts +++ b/server/tools/peertube.ts | |||
@@ -63,9 +63,10 @@ if (!process.argv.slice(2).length) { | |||
63 | 63 | ||
64 | getSettings() | 64 | getSettings() |
65 | .then(settings => { | 65 | .then(settings => { |
66 | const state = (settings.default === undefined || settings.default === -1) ? | 66 | const state = (settings.default === undefined || settings.default === -1) |
67 | 'no instance selected, commands will require explicit arguments' : | 67 | ? 'no instance selected, commands will require explicit arguments' |
68 | ('instance ' + settings.remotes[settings.default] + ' selected') | 68 | : 'instance ' + settings.remotes[settings.default] + ' selected' |
69 | |||
69 | program | 70 | program |
70 | .on('--help', function () { | 71 | .on('--help', function () { |
71 | console.log() | 72 | console.log() |
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..7ef68fc71 --- /dev/null +++ b/server/tools/yarn.lock | |||
@@ -0,0 +1,2063 @@ | |||
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. | ||
2 | # yarn lockfile v1 | ||
3 | |||
4 | |||
5 | abbrev@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 | |||
10 | addr-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 | |||
15 | airplay-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 | |||
23 | ansi-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 | |||
28 | ansi-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 | |||
33 | application-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 | |||
38 | application-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 | |||
46 | aproba@^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 | |||
51 | are-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 | |||
59 | ascli@~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 | |||
67 | async-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 | |||
72 | balanced-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 | |||
77 | bencode@^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 | |||
84 | binary-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 | |||
89 | bitfield@^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 | |||
94 | bittorrent-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 | |||
112 | bittorrent-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 | |||
117 | bittorrent-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 | |||
131 | bittorrent-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 | |||
161 | blob-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 | |||
166 | block-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 | |||
175 | bn.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 | |||
180 | brace-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 | |||
188 | browserify-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 | |||
193 | buffer-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 | |||
198 | buffer-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 | |||
206 | buffer-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 | |||
211 | buffer-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 | |||
216 | buffer-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 | |||
221 | buffer-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 | |||
226 | bufferutil@^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 | |||
233 | bufferview@~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 | |||
246 | camelcase@^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 | |||
251 | castv2-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 | |||
259 | castv2@~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 | |||
267 | chownr@^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 | |||
272 | chromecasts@^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 | |||
288 | chunk-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 | |||
296 | cli-table@^0.3.1: | ||
297 | version "0.3.1" | ||
298 | resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" | ||
299 | integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= | ||
300 | dependencies: | ||
301 | colors "1.0.3" | ||
302 | |||
303 | cliui@^3.2.0: | ||
304 | version "3.2.0" | ||
305 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" | ||
306 | integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= | ||
307 | dependencies: | ||
308 | string-width "^1.0.1" | ||
309 | strip-ansi "^3.0.1" | ||
310 | wrap-ansi "^2.0.0" | ||
311 | |||
312 | clivas@^0.2.0: | ||
313 | version "0.2.0" | ||
314 | resolved "https://registry.yarnpkg.com/clivas/-/clivas-0.2.0.tgz#b8d19188b3243e390f302410bd0cb1622db82649" | ||
315 | integrity sha1-uNGRiLMkPjkPMCQQvQyxYi24Jkk= | ||
316 | |||
317 | closest-to@~2.0.0: | ||
318 | version "2.0.0" | ||
319 | resolved "https://registry.yarnpkg.com/closest-to/-/closest-to-2.0.0.tgz#bb2a860edb7769b62d04821748ae50da24dbefaa" | ||
320 | integrity sha1-uyqGDtt3abYtBIIXSK5Q2iTb76o= | ||
321 | |||
322 | code-point-at@^1.0.0: | ||
323 | version "1.1.0" | ||
324 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" | ||
325 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= | ||
326 | |||
327 | colors@1.0.3: | ||
328 | version "1.0.3" | ||
329 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" | ||
330 | integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= | ||
331 | |||
332 | colour@latest: | ||
333 | version "0.7.1" | ||
334 | resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778" | ||
335 | integrity sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g= | ||
336 | |||
337 | compact2string@^1.2.0: | ||
338 | version "1.4.1" | ||
339 | resolved "https://registry.yarnpkg.com/compact2string/-/compact2string-1.4.1.tgz#8d34929055f8300a13cfc030ad1832e2e53c2e25" | ||
340 | integrity sha512-3D+EY5nsRhqnOwDxveBv5T8wGo4DEvYxjDtPGmdOX+gfr5gE92c2RC0w2wa+xEefm07QuVqqcF3nZJUZ92l/og== | ||
341 | dependencies: | ||
342 | ipaddr.js ">= 0.1.5" | ||
343 | |||
344 | concat-map@0.0.1: | ||
345 | version "0.0.1" | ||
346 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" | ||
347 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= | ||
348 | |||
349 | concat-stream@^1.4.8: | ||
350 | version "1.6.2" | ||
351 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" | ||
352 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== | ||
353 | dependencies: | ||
354 | buffer-from "^1.0.0" | ||
355 | inherits "^2.0.3" | ||
356 | readable-stream "^2.2.2" | ||
357 | typedarray "^0.0.6" | ||
358 | |||
359 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: | ||
360 | version "1.1.0" | ||
361 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" | ||
362 | integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= | ||
363 | |||
364 | core-util-is@~1.0.0: | ||
365 | version "1.0.2" | ||
366 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" | ||
367 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= | ||
368 | |||
369 | create-torrent@^3.23.1, create-torrent@^3.33.0: | ||
370 | version "3.33.0" | ||
371 | resolved "https://registry.yarnpkg.com/create-torrent/-/create-torrent-3.33.0.tgz#8a7a2aa2213a799c266c40e4c12f1468ede25105" | ||
372 | integrity sha512-KMd0KuvwVUg1grlRd5skG9ZkSbBYDDkAjDUMLnvxdRn0rL7ph3IwoOk7I8u1yLX4HYjGiLVlWYO55YWNNPjJFA== | ||
373 | dependencies: | ||
374 | bencode "^2.0.0" | ||
375 | block-stream2 "^1.0.0" | ||
376 | filestream "^4.0.0" | ||
377 | flatten "^1.0.2" | ||
378 | is-file "^1.0.0" | ||
379 | junk "^2.1.0" | ||
380 | minimist "^1.1.0" | ||
381 | multistream "^2.0.2" | ||
382 | once "^1.3.0" | ||
383 | piece-length "^1.0.0" | ||
384 | readable-stream "^3.0.2" | ||
385 | run-parallel "^1.0.0" | ||
386 | simple-sha1 "^2.0.0" | ||
387 | |||
388 | cross-spawn@^6.0.0: | ||
389 | version "6.0.5" | ||
390 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" | ||
391 | integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== | ||
392 | dependencies: | ||
393 | nice-try "^1.0.4" | ||
394 | path-key "^2.0.1" | ||
395 | semver "^5.5.0" | ||
396 | shebang-command "^1.2.0" | ||
397 | which "^1.2.9" | ||
398 | |||
399 | debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: | ||
400 | version "2.6.9" | ||
401 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" | ||
402 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== | ||
403 | dependencies: | ||
404 | ms "2.0.0" | ||
405 | |||
406 | debug@^3.1.0, debug@^3.2.6: | ||
407 | version "3.2.6" | ||
408 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" | ||
409 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== | ||
410 | dependencies: | ||
411 | ms "^2.1.1" | ||
412 | |||
413 | debug@^4.0.1, debug@^4.1.0: | ||
414 | version "4.1.1" | ||
415 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" | ||
416 | integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== | ||
417 | dependencies: | ||
418 | ms "^2.1.1" | ||
419 | |||
420 | decamelize@^1.1.1: | ||
421 | version "1.2.0" | ||
422 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" | ||
423 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= | ||
424 | |||
425 | decompress-response@^3.3.0: | ||
426 | version "3.3.0" | ||
427 | resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" | ||
428 | integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= | ||
429 | dependencies: | ||
430 | mimic-response "^1.0.0" | ||
431 | |||
432 | deep-extend@^0.6.0: | ||
433 | version "0.6.0" | ||
434 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" | ||
435 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== | ||
436 | |||
437 | defined@^1.0.0: | ||
438 | version "1.0.0" | ||
439 | resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" | ||
440 | integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= | ||
441 | |||
442 | delegates@^1.0.0: | ||
443 | version "1.0.0" | ||
444 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" | ||
445 | integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= | ||
446 | |||
447 | detect-libc@^1.0.2: | ||
448 | version "1.0.3" | ||
449 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" | ||
450 | integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= | ||
451 | |||
452 | dlnacasts@^0.1.0: | ||
453 | version "0.1.0" | ||
454 | resolved "https://registry.yarnpkg.com/dlnacasts/-/dlnacasts-0.1.0.tgz#f805211dcac74f6bb3a4d5d5541ad783b1b67d22" | ||
455 | integrity sha1-+AUhHcrHT2uzpNXVVBrXg7G2fSI= | ||
456 | dependencies: | ||
457 | debug "^2.1.3" | ||
458 | mime "^1.3.4" | ||
459 | node-ssdp "^2.7.1" | ||
460 | run-parallel "^1.1.6" | ||
461 | simple-get "^2.1.0" | ||
462 | thunky "^0.1.0" | ||
463 | upnp-mediarenderer-client "^1.2.2" | ||
464 | xml2js "^0.4.8" | ||
465 | |||
466 | dns-packet@^1.3.1: | ||
467 | version "1.3.1" | ||
468 | resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" | ||
469 | integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg== | ||
470 | dependencies: | ||
471 | ip "^1.1.0" | ||
472 | safe-buffer "^5.0.1" | ||
473 | |||
474 | dns-txt@^2.0.2: | ||
475 | version "2.0.2" | ||
476 | resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" | ||
477 | integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= | ||
478 | dependencies: | ||
479 | buffer-indexof "^1.0.0" | ||
480 | |||
481 | domexception@^1.0.1: | ||
482 | version "1.0.1" | ||
483 | resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" | ||
484 | integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== | ||
485 | dependencies: | ||
486 | webidl-conversions "^4.0.2" | ||
487 | |||
488 | ecstatic@^3.0.0: | ||
489 | version "3.3.2" | ||
490 | resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.2.tgz#6d1dd49814d00594682c652adb66076a69d46c48" | ||
491 | integrity sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog== | ||
492 | dependencies: | ||
493 | he "^1.1.1" | ||
494 | mime "^1.6.0" | ||
495 | minimist "^1.1.0" | ||
496 | url-join "^2.0.5" | ||
497 | |||
498 | elementtree@^0.1.6, elementtree@~0.1.6: | ||
499 | version "0.1.7" | ||
500 | resolved "https://registry.yarnpkg.com/elementtree/-/elementtree-0.1.7.tgz#9ac91be6e52fb6e6244c4e54a4ac3ed8ae8e29c0" | ||
501 | integrity sha1-mskb5uUvtuYkTE5UpKw+2K6OKcA= | ||
502 | dependencies: | ||
503 | sax "1.1.4" | ||
504 | |||
505 | end-of-stream@^1.1.0: | ||
506 | version "1.4.1" | ||
507 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" | ||
508 | integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== | ||
509 | dependencies: | ||
510 | once "^1.4.0" | ||
511 | |||
512 | error-ex@^1.2.0: | ||
513 | version "1.3.2" | ||
514 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" | ||
515 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== | ||
516 | dependencies: | ||
517 | is-arrayish "^0.2.1" | ||
518 | |||
519 | execa@^0.10.0: | ||
520 | version "0.10.0" | ||
521 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" | ||
522 | integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== | ||
523 | dependencies: | ||
524 | cross-spawn "^6.0.0" | ||
525 | get-stream "^3.0.0" | ||
526 | is-stream "^1.1.0" | ||
527 | npm-run-path "^2.0.0" | ||
528 | p-finally "^1.0.0" | ||
529 | signal-exit "^3.0.0" | ||
530 | strip-eof "^1.0.0" | ||
531 | |||
532 | executable@^4.0.0: | ||
533 | version "4.1.1" | ||
534 | resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" | ||
535 | integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== | ||
536 | dependencies: | ||
537 | pify "^2.2.0" | ||
538 | |||
539 | filestream@^4.0.0: | ||
540 | version "4.1.3" | ||
541 | resolved "https://registry.yarnpkg.com/filestream/-/filestream-4.1.3.tgz#948fcaade8221f715f5ecaddc54862faaacc9325" | ||
542 | integrity sha1-lI/KregiH3FfXsrdxUhi+qrMkyU= | ||
543 | dependencies: | ||
544 | inherits "^2.0.1" | ||
545 | readable-stream "^2.0.5" | ||
546 | typedarray-to-buffer "^3.0.0" | ||
547 | xtend "^4.0.1" | ||
548 | |||
549 | find-up@^1.0.0: | ||
550 | version "1.1.2" | ||
551 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" | ||
552 | integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= | ||
553 | dependencies: | ||
554 | path-exists "^2.0.0" | ||
555 | pinkie-promise "^2.0.0" | ||
556 | |||
557 | flatten@^1.0.2: | ||
558 | version "1.0.2" | ||
559 | resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" | ||
560 | integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I= | ||
561 | |||
562 | fs-chunk-store@^1.6.2: | ||
563 | version "1.7.0" | ||
564 | resolved "https://registry.yarnpkg.com/fs-chunk-store/-/fs-chunk-store-1.7.0.tgz#1c4bcbe93c99af10aa04b65348f2bb27377a4010" | ||
565 | integrity sha512-KhjJmZAs2eqfhCb6PdPx4RcZtheGTz86tpTC5JTvqBn/xda+Nb+0C7dCyjOSN7T76H6a56LvH0SVXQMchLXDRw== | ||
566 | dependencies: | ||
567 | mkdirp "^0.5.1" | ||
568 | random-access-file "^2.0.1" | ||
569 | randombytes "^2.0.3" | ||
570 | rimraf "^2.4.2" | ||
571 | run-parallel "^1.1.2" | ||
572 | thunky "^1.0.1" | ||
573 | |||
574 | fs-minipass@^1.2.5: | ||
575 | version "1.2.6" | ||
576 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" | ||
577 | integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== | ||
578 | dependencies: | ||
579 | minipass "^2.2.1" | ||
580 | |||
581 | fs.realpath@^1.0.0: | ||
582 | version "1.0.0" | ||
583 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" | ||
584 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= | ||
585 | |||
586 | gauge@~2.7.3: | ||
587 | version "2.7.4" | ||
588 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" | ||
589 | integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= | ||
590 | dependencies: | ||
591 | aproba "^1.0.3" | ||
592 | console-control-strings "^1.0.0" | ||
593 | has-unicode "^2.0.0" | ||
594 | object-assign "^4.1.0" | ||
595 | signal-exit "^3.0.0" | ||
596 | string-width "^1.0.1" | ||
597 | strip-ansi "^3.0.1" | ||
598 | wide-align "^1.1.0" | ||
599 | |||
600 | get-browser-rtc@^1.0.0: | ||
601 | version "1.0.2" | ||
602 | resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz#bbcd40c8451a7ed4ef5c373b8169a409dd1d11d9" | ||
603 | integrity sha1-u81AyEUaftTvXDc7gWmkCd0dEdk= | ||
604 | |||
605 | get-caller-file@^1.0.1: | ||
606 | version "1.0.3" | ||
607 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" | ||
608 | integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== | ||
609 | |||
610 | get-stdin@^6.0.0: | ||
611 | version "6.0.0" | ||
612 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" | ||
613 | integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== | ||
614 | |||
615 | get-stream@^3.0.0: | ||
616 | version "3.0.0" | ||
617 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" | ||
618 | integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= | ||
619 | |||
620 | glob@^7.1.3: | ||
621 | version "7.1.4" | ||
622 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" | ||
623 | integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== | ||
624 | dependencies: | ||
625 | fs.realpath "^1.0.0" | ||
626 | inflight "^1.0.4" | ||
627 | inherits "2" | ||
628 | minimatch "^3.0.4" | ||
629 | once "^1.3.0" | ||
630 | path-is-absolute "^1.0.0" | ||
631 | |||
632 | graceful-fs@^4.1.2: | ||
633 | version "4.1.15" | ||
634 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" | ||
635 | integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== | ||
636 | |||
637 | has-unicode@^2.0.0: | ||
638 | version "2.0.1" | ||
639 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" | ||
640 | integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= | ||
641 | |||
642 | he@^1.1.1: | ||
643 | version "1.2.0" | ||
644 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" | ||
645 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== | ||
646 | |||
647 | hosted-git-info@^2.1.4: | ||
648 | version "2.7.1" | ||
649 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" | ||
650 | integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== | ||
651 | |||
652 | iconv-lite@^0.4.4: | ||
653 | version "0.4.24" | ||
654 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" | ||
655 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== | ||
656 | dependencies: | ||
657 | safer-buffer ">= 2.1.2 < 3" | ||
658 | |||
659 | ignore-walk@^3.0.1: | ||
660 | version "3.0.1" | ||
661 | resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" | ||
662 | integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== | ||
663 | dependencies: | ||
664 | minimatch "^3.0.4" | ||
665 | |||
666 | immediate-chunk-store@^2.0.0: | ||
667 | version "2.0.0" | ||
668 | resolved "https://registry.yarnpkg.com/immediate-chunk-store/-/immediate-chunk-store-2.0.0.tgz#f313fd0cc71396d8911ad031179e1cccfda3da18" | ||
669 | integrity sha512-5s6NiCGbtWc+OQA60jrre54w12U7tynIyUNjO5LJjNA5lWwvCv6640roq8Wk/wIuaqnd4Pgtp453OyJ7hbONkQ== | ||
670 | |||
671 | inflight@^1.0.4: | ||
672 | version "1.0.6" | ||
673 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" | ||
674 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= | ||
675 | dependencies: | ||
676 | once "^1.3.0" | ||
677 | wrappy "1" | ||
678 | |||
679 | inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: | ||
680 | version "2.0.3" | ||
681 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" | ||
682 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= | ||
683 | |||
684 | ini@~1.3.0: | ||
685 | version "1.3.5" | ||
686 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" | ||
687 | integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== | ||
688 | |||
689 | invert-kv@^1.0.0: | ||
690 | version "1.0.0" | ||
691 | resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" | ||
692 | integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= | ||
693 | |||
694 | ip-set@^1.0.0: | ||
695 | version "1.0.2" | ||
696 | resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.2.tgz#be4f119f82c124836455993dfcd554639c7007de" | ||
697 | integrity sha512-Mb6kv78bTi4RNAIIWL8Bbre7hXOR2pNUi3j8FaQkLaitf/ZWxkq3/iIwXNYk2ACO3IMfdVdQrOkUtwZblO7uBA== | ||
698 | dependencies: | ||
699 | ip "^1.1.3" | ||
700 | |||
701 | ip@^1.0.1, ip@^1.1.0, ip@^1.1.3: | ||
702 | version "1.1.5" | ||
703 | resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" | ||
704 | integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= | ||
705 | |||
706 | "ipaddr.js@>= 0.1.5", ipaddr.js@^1.0.1: | ||
707 | version "1.9.0" | ||
708 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" | ||
709 | integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== | ||
710 | |||
711 | is-arrayish@^0.2.1: | ||
712 | version "0.2.1" | ||
713 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" | ||
714 | integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= | ||
715 | |||
716 | is-ascii@^1.0.0: | ||
717 | version "1.0.0" | ||
718 | resolved "https://registry.yarnpkg.com/is-ascii/-/is-ascii-1.0.0.tgz#f02ad0259a0921cd199ff21ce1b09e0f6b4e3929" | ||
719 | integrity sha1-8CrQJZoJIc0Zn/Ic4bCeD2tOOSk= | ||
720 | |||
721 | is-file@^1.0.0: | ||
722 | version "1.0.0" | ||
723 | resolved "https://registry.yarnpkg.com/is-file/-/is-file-1.0.0.tgz#28a44cfbd9d3db193045f22b65fce8edf9620596" | ||
724 | integrity sha1-KKRM+9nT2xkwRfIrZfzo7fliBZY= | ||
725 | |||
726 | is-fullwidth-code-point@^1.0.0: | ||
727 | version "1.0.0" | ||
728 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" | ||
729 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= | ||
730 | dependencies: | ||
731 | number-is-nan "^1.0.0" | ||
732 | |||
733 | is-fullwidth-code-point@^2.0.0: | ||
734 | version "2.0.0" | ||
735 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" | ||
736 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= | ||
737 | |||
738 | is-stream@^1.1.0: | ||
739 | version "1.1.0" | ||
740 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" | ||
741 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= | ||
742 | |||
743 | is-typedarray@^1.0.0: | ||
744 | version "1.0.0" | ||
745 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" | ||
746 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= | ||
747 | |||
748 | is-utf8@^0.2.0: | ||
749 | version "0.2.1" | ||
750 | resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" | ||
751 | integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= | ||
752 | |||
753 | isarray@~1.0.0: | ||
754 | version "1.0.0" | ||
755 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" | ||
756 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= | ||
757 | |||
758 | isexe@^2.0.0: | ||
759 | version "2.0.0" | ||
760 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" | ||
761 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= | ||
762 | |||
763 | junk@^2.1.0: | ||
764 | version "2.1.0" | ||
765 | resolved "https://registry.yarnpkg.com/junk/-/junk-2.1.0.tgz#f431b4b7f072dc500a5f10ce7f4ec71930e70134" | ||
766 | integrity sha1-9DG0t/By3FAKXxDOf07HGTDnATQ= | ||
767 | |||
768 | k-bucket@^4.0.0: | ||
769 | version "4.0.1" | ||
770 | resolved "https://registry.yarnpkg.com/k-bucket/-/k-bucket-4.0.1.tgz#3fc2e5693f0b7bff90d7b6b476edd6087955d542" | ||
771 | integrity sha512-YvDpmY3waI999h1zZoW1rJ04fZrgZ+5PAlVmvwDHT6YO/Q1AOhdel07xsKy9eAvJjQ9xZV1wz3rXKqEfaWvlcQ== | ||
772 | dependencies: | ||
773 | inherits "^2.0.1" | ||
774 | randombytes "^2.0.3" | ||
775 | |||
776 | k-bucket@^5.0.0: | ||
777 | version "5.0.0" | ||
778 | resolved "https://registry.yarnpkg.com/k-bucket/-/k-bucket-5.0.0.tgz#ef7a401fcd4c37cd31dceaa6ae4440ca91055e01" | ||
779 | integrity sha512-r/q+wV/Kde62/tk+rqyttEJn6h0jR7x+incdMVSYTqK73zVxVrzJa70kJL49cIKen8XjIgUZKSvk8ktnrQbK4w== | ||
780 | dependencies: | ||
781 | randombytes "^2.0.3" | ||
782 | |||
783 | k-rpc-socket@^1.7.2: | ||
784 | version "1.8.0" | ||
785 | resolved "https://registry.yarnpkg.com/k-rpc-socket/-/k-rpc-socket-1.8.0.tgz#9a4dd6a4f3795ed847ffa156579cc389990bd1f2" | ||
786 | integrity sha512-f/9TynsO8YYjZ6JjNNtSSH7CJcIHcio1buy3zqByGxb/GX8AWLdL6FZEWTrN8V3/J7W4/E0ZTQQ+Jt2rVq7ELg== | ||
787 | dependencies: | ||
788 | bencode "^2.0.0" | ||
789 | buffer-equals "^1.0.4" | ||
790 | safe-buffer "^5.1.1" | ||
791 | |||
792 | k-rpc@^5.0.0: | ||
793 | version "5.0.0" | ||
794 | resolved "https://registry.yarnpkg.com/k-rpc/-/k-rpc-5.0.0.tgz#a72651860c96db440579e4c9f38dce8a42b481a8" | ||
795 | integrity sha512-vCH2rQdfMOS+MlUuTSuar1pS2EMrltURf9LmAR9xR6Jik0XPlMX3vEixgqMn17wKmFVCublJqSJ4hJIP7oKZ3Q== | ||
796 | dependencies: | ||
797 | buffer-equals "^1.0.3" | ||
798 | k-bucket "^4.0.0" | ||
799 | k-rpc-socket "^1.7.2" | ||
800 | randombytes "^2.0.5" | ||
801 | safe-buffer "^5.1.1" | ||
802 | |||
803 | last-one-wins@^1.0.4: | ||
804 | version "1.0.4" | ||
805 | resolved "https://registry.yarnpkg.com/last-one-wins/-/last-one-wins-1.0.4.tgz#c1bfd0cbcb46790ec9156b8d1aee8fcb86cda22a" | ||
806 | integrity sha1-wb/Qy8tGeQ7JFWuNGu6Py4bNoio= | ||
807 | |||
808 | lcid@^1.0.0: | ||
809 | version "1.0.0" | ||
810 | resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" | ||
811 | integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= | ||
812 | dependencies: | ||
813 | invert-kv "^1.0.0" | ||
814 | |||
815 | load-ip-set@^2.1.0: | ||
816 | version "2.1.0" | ||
817 | resolved "https://registry.yarnpkg.com/load-ip-set/-/load-ip-set-2.1.0.tgz#2d50b737cae41de4e413d213991d4083a3e1784b" | ||
818 | integrity sha512-taz7U6B+F7Zq90dfIKwqsB1CrFKelSEmMGC68OUqem8Cgd1QZygQBYb2Fk9i6muBSfH4xwF/Pjt4KKlAdOyWZw== | ||
819 | dependencies: | ||
820 | ip-set "^1.0.0" | ||
821 | netmask "^1.0.6" | ||
822 | once "^1.3.0" | ||
823 | simple-get "^3.0.0" | ||
824 | split "^1.0.0" | ||
825 | |||
826 | load-json-file@^1.0.0: | ||
827 | version "1.1.0" | ||
828 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" | ||
829 | integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= | ||
830 | dependencies: | ||
831 | graceful-fs "^4.1.2" | ||
832 | parse-json "^2.2.0" | ||
833 | pify "^2.0.0" | ||
834 | pinkie-promise "^2.0.0" | ||
835 | strip-bom "^2.0.0" | ||
836 | |||
837 | "long@~2 >=2.2.3": | ||
838 | version "2.4.0" | ||
839 | resolved "https://registry.yarnpkg.com/long/-/long-2.4.0.tgz#9fa180bb1d9500cdc29c4156766a1995e1f4524f" | ||
840 | integrity sha1-n6GAux2VAM3CnEFWdmoZleH0Uk8= | ||
841 | |||
842 | lru@^3.0.0, lru@^3.1.0: | ||
843 | version "3.1.0" | ||
844 | resolved "https://registry.yarnpkg.com/lru/-/lru-3.1.0.tgz#ea7fb8546d83733396a13091d76cfeb4c06837d5" | ||
845 | integrity sha1-6n+4VG2DczOWoTCR12z+tMBoN9U= | ||
846 | dependencies: | ||
847 | inherits "^2.0.1" | ||
848 | |||
849 | magnet-uri@^5.1.3: | ||
850 | version "5.2.4" | ||
851 | resolved "https://registry.yarnpkg.com/magnet-uri/-/magnet-uri-5.2.4.tgz#7afe5b736af04445aff744c93a890a3710077688" | ||
852 | integrity sha512-VYaJMxhr8B9BrCiNINUsuhaEe40YnG+AQBwcqUKO66lSVaI9I3A1iH/6EmEwRI8OYUg5Gt+4lLE7achg676lrg== | ||
853 | dependencies: | ||
854 | thirty-two "^1.0.1" | ||
855 | uniq "^1.0.1" | ||
856 | |||
857 | mdns-js-packet@~0.2.0: | ||
858 | version "0.2.0" | ||
859 | resolved "https://registry.yarnpkg.com/mdns-js-packet/-/mdns-js-packet-0.2.0.tgz#642409e8183c7561cc60615bbd1420ec2fad7616" | ||
860 | integrity sha1-ZCQJ6Bg8dWHMYGFbvRQg7C+tdhY= | ||
861 | dependencies: | ||
862 | debug "^2.1.0" | ||
863 | qap "^3.1.2" | ||
864 | |||
865 | mdns-js@0.5.0: | ||
866 | version "0.5.0" | ||
867 | resolved "https://registry.yarnpkg.com/mdns-js/-/mdns-js-0.5.0.tgz#4c8abb6ba7cabdc892d39228c3faa2556e09cf87" | ||
868 | integrity sha1-TIq7a6fKvciS05Iow/qiVW4Jz4c= | ||
869 | dependencies: | ||
870 | debug "^2.1.1" | ||
871 | mdns-js-packet "~0.2.0" | ||
872 | semver "~5.1.0" | ||
873 | |||
874 | mediasource@^2.1.0, mediasource@^2.2.2: | ||
875 | version "2.3.0" | ||
876 | resolved "https://registry.yarnpkg.com/mediasource/-/mediasource-2.3.0.tgz#4c7b49e7ea4fb88f1cc181d8fcf0d94649271dc6" | ||
877 | integrity sha512-fqm86UwHvAnneIv40Uy1sDQaFtAByq/k0SQ3uCtbnEeSQNT1s5TDHCZOD1VmYCHwfY1jL2NjoZVwzZKYqy3L7A== | ||
878 | dependencies: | ||
879 | inherits "^2.0.1" | ||
880 | readable-stream "^3.0.0" | ||
881 | to-arraybuffer "^1.0.1" | ||
882 | |||
883 | memory-chunk-store@^1.2.0: | ||
884 | version "1.3.0" | ||
885 | resolved "https://registry.yarnpkg.com/memory-chunk-store/-/memory-chunk-store-1.3.0.tgz#ae99e7e3b58b52db43d49d94722930d39459d0c4" | ||
886 | integrity sha512-6LsOpHKKhxYrLhHmOJdBCUtSO7op5rUs1pag0fhjHo0QiXRyna0bwYf4EmQuL7InUeF2J7dUMPr6VMogRyf9NA== | ||
887 | |||
888 | mime@^1.3.4, mime@^1.6.0: | ||
889 | version "1.6.0" | ||
890 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" | ||
891 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== | ||
892 | |||
893 | mime@^2.1.0, mime@^2.4.0: | ||
894 | version "2.4.3" | ||
895 | resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe" | ||
896 | integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw== | ||
897 | |||
898 | mimic-response@^1.0.0: | ||
899 | version "1.0.1" | ||
900 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" | ||
901 | integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== | ||
902 | |||
903 | minimatch@^3.0.4: | ||
904 | version "3.0.4" | ||
905 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" | ||
906 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== | ||
907 | dependencies: | ||
908 | brace-expansion "^1.1.7" | ||
909 | |||
910 | minimist@0.0.8: | ||
911 | version "0.0.8" | ||
912 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" | ||
913 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= | ||
914 | |||
915 | minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0: | ||
916 | version "1.2.0" | ||
917 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" | ||
918 | integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= | ||
919 | |||
920 | minipass@^2.2.1, minipass@^2.3.4: | ||
921 | version "2.3.5" | ||
922 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" | ||
923 | integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== | ||
924 | dependencies: | ||
925 | safe-buffer "^5.1.2" | ||
926 | yallist "^3.0.0" | ||
927 | |||
928 | minizlib@^1.1.1: | ||
929 | version "1.2.1" | ||
930 | resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" | ||
931 | integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== | ||
932 | dependencies: | ||
933 | minipass "^2.2.1" | ||
934 | |||
935 | mkdirp@^0.5.0, mkdirp@^0.5.1: | ||
936 | version "0.5.1" | ||
937 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" | ||
938 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= | ||
939 | dependencies: | ||
940 | minimist "0.0.8" | ||
941 | |||
942 | moment@^2.12.0: | ||
943 | version "2.24.0" | ||
944 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" | ||
945 | integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== | ||
946 | |||
947 | mp4-box-encoding@^1.1.0, mp4-box-encoding@^1.3.0: | ||
948 | version "1.3.0" | ||
949 | resolved "https://registry.yarnpkg.com/mp4-box-encoding/-/mp4-box-encoding-1.3.0.tgz#2a6f750947ff68c3a498fd76cd6424c53d995d48" | ||
950 | integrity sha512-U4pMLpjT/UzB8d36dxj6Mf1bG9xypEvgbuRIa1fztRXNKKTCAtRxsnFZhNOd7YDFOKtjBgssYGvo4H/Q3ZY1MA== | ||
951 | dependencies: | ||
952 | buffer-alloc "^1.2.0" | ||
953 | buffer-from "^1.1.0" | ||
954 | uint64be "^2.0.2" | ||
955 | |||
956 | mp4-stream@^2.0.0: | ||
957 | version "2.0.3" | ||
958 | resolved "https://registry.yarnpkg.com/mp4-stream/-/mp4-stream-2.0.3.tgz#30acee07709d323f8dcd87a07b3ce9c3c4bfb364" | ||
959 | integrity sha512-5NzgI0+bGakoZEwnIYINXqB3mnewkt3Y7jcvkXsTubnCNUSdM8cpP0Vemxf6FLg0qUN8fydTgNMVAc3QU8B92g== | ||
960 | dependencies: | ||
961 | buffer-alloc "^1.1.0" | ||
962 | inherits "^2.0.1" | ||
963 | mp4-box-encoding "^1.1.0" | ||
964 | next-event "^1.0.0" | ||
965 | readable-stream "^2.0.3" | ||
966 | |||
967 | ms@2.0.0: | ||
968 | version "2.0.0" | ||
969 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" | ||
970 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= | ||
971 | |||
972 | ms@^2.1.1: | ||
973 | version "2.1.1" | ||
974 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" | ||
975 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== | ||
976 | |||
977 | multicast-dns@^6.0.1: | ||
978 | version "6.2.3" | ||
979 | resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" | ||
980 | integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== | ||
981 | dependencies: | ||
982 | dns-packet "^1.3.1" | ||
983 | thunky "^1.0.2" | ||
984 | |||
985 | multistream@^2.0.2, multistream@^2.0.5: | ||
986 | version "2.1.1" | ||
987 | resolved "https://registry.yarnpkg.com/multistream/-/multistream-2.1.1.tgz#629d3a29bd76623489980d04519a2c365948148c" | ||
988 | integrity sha512-xasv76hl6nr1dEy3lPvy7Ej7K/Lx3O/FCvwge8PeVJpciPPoNCbaANcNiBug3IpdvTveZUcAV0DJzdnUDMesNQ== | ||
989 | dependencies: | ||
990 | inherits "^2.0.1" | ||
991 | readable-stream "^2.0.5" | ||
992 | |||
993 | nan@*, nan@^2.3.2: | ||
994 | version "2.14.0" | ||
995 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" | ||
996 | integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== | ||
997 | |||
998 | needle@^2.2.1: | ||
999 | version "2.4.0" | ||
1000 | resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" | ||
1001 | integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== | ||
1002 | dependencies: | ||
1003 | debug "^3.2.6" | ||
1004 | iconv-lite "^0.4.4" | ||
1005 | sax "^1.2.4" | ||
1006 | |||
1007 | netmask@^1.0.6: | ||
1008 | version "1.0.6" | ||
1009 | resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" | ||
1010 | integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU= | ||
1011 | |||
1012 | netrc-parser@^3.1.6: | ||
1013 | version "3.1.6" | ||
1014 | resolved "https://registry.yarnpkg.com/netrc-parser/-/netrc-parser-3.1.6.tgz#7243c9ec850b8e805b9bdc7eae7b1450d4a96e72" | ||
1015 | integrity sha512-lY+fmkqSwntAAjfP63jB4z5p5WbuZwyMCD3pInT7dpHU/Gc6Vv90SAC6A0aNiqaRGHiuZFBtiwu+pu8W/Eyotw== | ||
1016 | dependencies: | ||
1017 | debug "^3.1.0" | ||
1018 | execa "^0.10.0" | ||
1019 | |||
1020 | network-address@^1.0.0, network-address@^1.1.0: | ||
1021 | version "1.1.2" | ||
1022 | resolved "https://registry.yarnpkg.com/network-address/-/network-address-1.1.2.tgz#4aa7bfd43f03f0b81c9702b13d6a858ddb326f3e" | ||
1023 | integrity sha1-Sqe/1D8D8LgclwKxPWqFjdsybz4= | ||
1024 | |||
1025 | next-event@^1.0.0: | ||
1026 | version "1.0.0" | ||
1027 | resolved "https://registry.yarnpkg.com/next-event/-/next-event-1.0.0.tgz#e7778acde2e55802e0ad1879c39cf6f75eda61d8" | ||
1028 | integrity sha1-53eKzeLlWALgrRh5w5z2917aYdg= | ||
1029 | |||
1030 | nice-try@^1.0.4: | ||
1031 | version "1.0.5" | ||
1032 | resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" | ||
1033 | integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== | ||
1034 | |||
1035 | node-cmake@2.3.2: | ||
1036 | version "2.3.2" | ||
1037 | resolved "https://registry.yarnpkg.com/node-cmake/-/node-cmake-2.3.2.tgz#e0fbc54b11405b07705e4d6d41865ae95ad289d0" | ||
1038 | integrity sha1-4PvFSxFAWwdwXk1tQYZa6VrSidA= | ||
1039 | dependencies: | ||
1040 | nan "*" | ||
1041 | which "^1.2.14" | ||
1042 | yargs "^7.0.2" | ||
1043 | |||
1044 | node-gyp-build@~3.7.0: | ||
1045 | version "3.7.0" | ||
1046 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d" | ||
1047 | integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w== | ||
1048 | |||
1049 | node-pre-gyp@0.11.x: | ||
1050 | version "0.11.0" | ||
1051 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" | ||
1052 | integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q== | ||
1053 | dependencies: | ||
1054 | detect-libc "^1.0.2" | ||
1055 | mkdirp "^0.5.1" | ||
1056 | needle "^2.2.1" | ||
1057 | nopt "^4.0.1" | ||
1058 | npm-packlist "^1.1.6" | ||
1059 | npmlog "^4.0.2" | ||
1060 | rc "^1.2.7" | ||
1061 | rimraf "^2.6.1" | ||
1062 | semver "^5.3.0" | ||
1063 | tar "^4" | ||
1064 | |||
1065 | node-ssdp@^2.2.0, node-ssdp@^2.7.1: | ||
1066 | version "2.9.1" | ||
1067 | resolved "https://registry.yarnpkg.com/node-ssdp/-/node-ssdp-2.9.1.tgz#2d6ba8e7eff9bf5b338564f91f7ac5d5cdddc55b" | ||
1068 | integrity sha1-LWuo5+/5v1szhWT5H3rF1c3dxVs= | ||
1069 | dependencies: | ||
1070 | debug "^2.2.0" | ||
1071 | ip "^1.0.1" | ||
1072 | |||
1073 | nodebmc@0.0.7: | ||
1074 | version "0.0.7" | ||
1075 | resolved "https://registry.yarnpkg.com/nodebmc/-/nodebmc-0.0.7.tgz#fae179165265509302cefbebeabd29bd4035184d" | ||
1076 | integrity sha1-+uF5FlJlUJMCzvvr6r0pvUA1GE0= | ||
1077 | dependencies: | ||
1078 | mdns-js "0.5.0" | ||
1079 | |||
1080 | nopt@^4.0.1: | ||
1081 | version "4.0.1" | ||
1082 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" | ||
1083 | integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= | ||
1084 | dependencies: | ||
1085 | abbrev "1" | ||
1086 | osenv "^0.1.4" | ||
1087 | |||
1088 | normalize-package-data@^2.3.2: | ||
1089 | version "2.5.0" | ||
1090 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" | ||
1091 | integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== | ||
1092 | dependencies: | ||
1093 | hosted-git-info "^2.1.4" | ||
1094 | resolve "^1.10.0" | ||
1095 | semver "2 || 3 || 4 || 5" | ||
1096 | validate-npm-package-license "^3.0.1" | ||
1097 | |||
1098 | npm-bundled@^1.0.1: | ||
1099 | version "1.0.6" | ||
1100 | resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" | ||
1101 | integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== | ||
1102 | |||
1103 | npm-packlist@^1.1.6: | ||
1104 | version "1.4.1" | ||
1105 | resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" | ||
1106 | integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw== | ||
1107 | dependencies: | ||
1108 | ignore-walk "^3.0.1" | ||
1109 | npm-bundled "^1.0.1" | ||
1110 | |||
1111 | npm-run-path@^2.0.0: | ||
1112 | version "2.0.2" | ||
1113 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" | ||
1114 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= | ||
1115 | dependencies: | ||
1116 | path-key "^2.0.0" | ||
1117 | |||
1118 | npmlog@^4.0.2: | ||
1119 | version "4.1.2" | ||
1120 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" | ||
1121 | integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== | ||
1122 | dependencies: | ||
1123 | are-we-there-yet "~1.1.2" | ||
1124 | console-control-strings "~1.1.0" | ||
1125 | gauge "~2.7.3" | ||
1126 | set-blocking "~2.0.0" | ||
1127 | |||
1128 | number-is-nan@^1.0.0: | ||
1129 | version "1.0.1" | ||
1130 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" | ||
1131 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= | ||
1132 | |||
1133 | object-assign@^4.1.0: | ||
1134 | version "4.1.1" | ||
1135 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" | ||
1136 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= | ||
1137 | |||
1138 | once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: | ||
1139 | version "1.4.0" | ||
1140 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" | ||
1141 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= | ||
1142 | dependencies: | ||
1143 | wrappy "1" | ||
1144 | |||
1145 | open@0.0.5: | ||
1146 | version "0.0.5" | ||
1147 | resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc" | ||
1148 | integrity sha1-QsPhjslUZra/DcQvOilFw/DK2Pw= | ||
1149 | |||
1150 | optjs@latest: | ||
1151 | version "3.2.2" | ||
1152 | resolved "https://registry.yarnpkg.com/optjs/-/optjs-3.2.2.tgz#69a6ce89c442a44403141ad2f9b370bd5bb6f4ee" | ||
1153 | integrity sha1-aabOicRCpEQDFBrS+bNwvVu29O4= | ||
1154 | |||
1155 | os-homedir@^1.0.0: | ||
1156 | version "1.0.2" | ||
1157 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" | ||
1158 | integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= | ||
1159 | |||
1160 | os-locale@^1.4.0: | ||
1161 | version "1.4.0" | ||
1162 | resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" | ||
1163 | integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= | ||
1164 | dependencies: | ||
1165 | lcid "^1.0.0" | ||
1166 | |||
1167 | os-tmpdir@^1.0.0: | ||
1168 | version "1.0.2" | ||
1169 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" | ||
1170 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= | ||
1171 | |||
1172 | osenv@^0.1.4: | ||
1173 | version "0.1.5" | ||
1174 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" | ||
1175 | integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== | ||
1176 | dependencies: | ||
1177 | os-homedir "^1.0.0" | ||
1178 | os-tmpdir "^1.0.0" | ||
1179 | |||
1180 | p-finally@^1.0.0: | ||
1181 | version "1.0.0" | ||
1182 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" | ||
1183 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= | ||
1184 | |||
1185 | package-json-versionify@^1.0.2: | ||
1186 | version "1.0.4" | ||
1187 | resolved "https://registry.yarnpkg.com/package-json-versionify/-/package-json-versionify-1.0.4.tgz#5860587a944873a6b7e6d26e8e51ffb22315bf17" | ||
1188 | integrity sha1-WGBYepRIc6a35tJujlH/siMVvxc= | ||
1189 | dependencies: | ||
1190 | browserify-package-json "^1.0.0" | ||
1191 | |||
1192 | parse-json@^2.2.0: | ||
1193 | version "2.2.0" | ||
1194 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" | ||
1195 | integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= | ||
1196 | dependencies: | ||
1197 | error-ex "^1.2.0" | ||
1198 | |||
1199 | parse-numeric-range@^0.0.2: | ||
1200 | version "0.0.2" | ||
1201 | resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4" | ||
1202 | integrity sha1-tPCdQTx6282Yf26SM8e0shDJOOQ= | ||
1203 | |||
1204 | parse-torrent@^6.0.0, parse-torrent@^6.1.2: | ||
1205 | version "6.1.2" | ||
1206 | resolved "https://registry.yarnpkg.com/parse-torrent/-/parse-torrent-6.1.2.tgz#99da5bdd23435a1cb7e8e7a63847c4efb21b1956" | ||
1207 | integrity sha512-Z/vig84sHwtrTEbOzisT4xnYTFlOgAaLQccPruMPgRahZUppVE/BUXzAos3jZM7c64o0lfukQdQ4ozWa5lN39w== | ||
1208 | dependencies: | ||
1209 | bencode "^2.0.0" | ||
1210 | blob-to-buffer "^1.2.6" | ||
1211 | get-stdin "^6.0.0" | ||
1212 | magnet-uri "^5.1.3" | ||
1213 | simple-get "^3.0.1" | ||
1214 | simple-sha1 "^2.0.0" | ||
1215 | uniq "^1.0.1" | ||
1216 | |||
1217 | path-exists@^2.0.0: | ||
1218 | version "2.1.0" | ||
1219 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" | ||
1220 | integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= | ||
1221 | dependencies: | ||
1222 | pinkie-promise "^2.0.0" | ||
1223 | |||
1224 | path-is-absolute@^1.0.0: | ||
1225 | version "1.0.1" | ||
1226 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" | ||
1227 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= | ||
1228 | |||
1229 | path-key@^2.0.0, path-key@^2.0.1: | ||
1230 | version "2.0.1" | ||
1231 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" | ||
1232 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= | ||
1233 | |||
1234 | path-parse@^1.0.6: | ||
1235 | version "1.0.6" | ||
1236 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" | ||
1237 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== | ||
1238 | |||
1239 | path-type@^1.0.0: | ||
1240 | version "1.1.0" | ||
1241 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" | ||
1242 | integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= | ||
1243 | dependencies: | ||
1244 | graceful-fs "^4.1.2" | ||
1245 | pify "^2.0.0" | ||
1246 | pinkie-promise "^2.0.0" | ||
1247 | |||
1248 | piece-length@^1.0.0: | ||
1249 | version "1.0.0" | ||
1250 | resolved "https://registry.yarnpkg.com/piece-length/-/piece-length-1.0.0.tgz#4db7167157fd69fef14caf7262cd39f189b24508" | ||
1251 | integrity sha1-TbcWcVf9af7xTK9yYs058YmyRQg= | ||
1252 | dependencies: | ||
1253 | closest-to "~2.0.0" | ||
1254 | |||
1255 | pify@^2.0.0, pify@^2.2.0: | ||
1256 | version "2.3.0" | ||
1257 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" | ||
1258 | integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= | ||
1259 | |||
1260 | pinkie-promise@^2.0.0: | ||
1261 | version "2.0.1" | ||
1262 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" | ||
1263 | integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= | ||
1264 | dependencies: | ||
1265 | pinkie "^2.0.0" | ||
1266 | |||
1267 | pinkie@^2.0.0: | ||
1268 | version "2.0.4" | ||
1269 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" | ||
1270 | integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= | ||
1271 | |||
1272 | plist-with-patches@0.5.1: | ||
1273 | version "0.5.1" | ||
1274 | resolved "https://registry.yarnpkg.com/plist-with-patches/-/plist-with-patches-0.5.1.tgz#868aae2e0df8989b026562b35cbc19cfd8bb780d" | ||
1275 | integrity sha1-hoquLg34mJsCZWKzXLwZz9i7eA0= | ||
1276 | dependencies: | ||
1277 | xmlbuilder "0.4.x" | ||
1278 | xmldom "0.1.x" | ||
1279 | |||
1280 | prettier-bytes@^1.0.3: | ||
1281 | version "1.0.4" | ||
1282 | resolved "https://registry.yarnpkg.com/prettier-bytes/-/prettier-bytes-1.0.4.tgz#994b02aa46f699c50b6257b5faaa7fe2557e62d6" | ||
1283 | integrity sha1-mUsCqkb2mcULYle1+qp/4lV+YtY= | ||
1284 | |||
1285 | process-nextick-args@~2.0.0: | ||
1286 | version "2.0.0" | ||
1287 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" | ||
1288 | integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== | ||
1289 | |||
1290 | protobufjs@^3.2.2: | ||
1291 | version "3.8.2" | ||
1292 | resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-3.8.2.tgz#bc826e34c3af4697e8d0af7a669e4d612aedcd17" | ||
1293 | integrity sha1-vIJuNMOvRpfo0K96Zp5NYSrtzRc= | ||
1294 | dependencies: | ||
1295 | ascli "~0.3" | ||
1296 | bytebuffer "~3 >=3.5" | ||
1297 | |||
1298 | pump@^3.0.0: | ||
1299 | version "3.0.0" | ||
1300 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" | ||
1301 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== | ||
1302 | dependencies: | ||
1303 | end-of-stream "^1.1.0" | ||
1304 | once "^1.3.1" | ||
1305 | |||
1306 | qap@^3.1.2: | ||
1307 | version "3.3.1" | ||
1308 | resolved "https://registry.yarnpkg.com/qap/-/qap-3.3.1.tgz#11f9e8fa8890fe7cb99210c0f44d0613b7372cac" | ||
1309 | integrity sha1-Efno+oiQ/ny5khDA9E0GE7c3LKw= | ||
1310 | |||
1311 | random-access-file@^2.0.1: | ||
1312 | version "2.1.2" | ||
1313 | resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-2.1.2.tgz#eeb32e50b9831f32060516862381152ae4e05aa6" | ||
1314 | integrity sha512-dZo7HEcEPbZ/6XLXC4GXypiWvFbXVkdeMrJTi0B94pBJwddt/AvJh8GaQhso6KGYROGYCI/VWdHbmRDtkwT9pQ== | ||
1315 | dependencies: | ||
1316 | mkdirp "^0.5.1" | ||
1317 | random-access-storage "^1.1.1" | ||
1318 | |||
1319 | random-access-storage@^1.1.1: | ||
1320 | version "1.3.0" | ||
1321 | resolved "https://registry.yarnpkg.com/random-access-storage/-/random-access-storage-1.3.0.tgz#d27e4d897b79dc4358afc2bbe553044e5c8cfe35" | ||
1322 | integrity sha512-pdS9Mcb9TB7oICypPRALlheaSuszuAKmLVEPKJMuYor7R/zDuHh5ALuQoS+ox31XRwQUL+tDwWH2GPdyspwelA== | ||
1323 | dependencies: | ||
1324 | inherits "^2.0.3" | ||
1325 | |||
1326 | random-iterate@^1.0.1: | ||
1327 | version "1.0.1" | ||
1328 | resolved "https://registry.yarnpkg.com/random-iterate/-/random-iterate-1.0.1.tgz#f7d97d92dee6665ec5f6da08c7f963cad4b2ac99" | ||
1329 | integrity sha1-99l9kt7mZl7F9toIx/ljytSyrJk= | ||
1330 | |||
1331 | randombytes@^2.0.3, randombytes@^2.0.5: | ||
1332 | version "2.1.0" | ||
1333 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" | ||
1334 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== | ||
1335 | dependencies: | ||
1336 | safe-buffer "^5.1.0" | ||
1337 | |||
1338 | range-parser@^1.2.0: | ||
1339 | version "1.2.1" | ||
1340 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" | ||
1341 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== | ||
1342 | |||
1343 | range-slice-stream@^2.0.0: | ||
1344 | version "2.0.0" | ||
1345 | resolved "https://registry.yarnpkg.com/range-slice-stream/-/range-slice-stream-2.0.0.tgz#1f25fc7a2cacf9ccd140c46f9cf670a1a7fe3ce6" | ||
1346 | integrity sha512-PPYLwZ63lXi6Tv2EZ8w3M4FzC0rVqvxivaOVS8pXSp5FMIHFnvi4MWHL3UdFLhwSy50aNtJsgjY0mBC6oFL26Q== | ||
1347 | dependencies: | ||
1348 | readable-stream "^3.0.2" | ||
1349 | |||
1350 | rc@^1.2.7: | ||
1351 | version "1.2.8" | ||
1352 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" | ||
1353 | integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== | ||
1354 | dependencies: | ||
1355 | deep-extend "^0.6.0" | ||
1356 | ini "~1.3.0" | ||
1357 | minimist "^1.2.0" | ||
1358 | strip-json-comments "~2.0.1" | ||
1359 | |||
1360 | read-pkg-up@^1.0.1: | ||
1361 | version "1.0.1" | ||
1362 | resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" | ||
1363 | integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= | ||
1364 | dependencies: | ||
1365 | find-up "^1.0.0" | ||
1366 | read-pkg "^1.0.0" | ||
1367 | |||
1368 | read-pkg@^1.0.0: | ||
1369 | version "1.1.0" | ||
1370 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" | ||
1371 | integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= | ||
1372 | dependencies: | ||
1373 | load-json-file "^1.0.0" | ||
1374 | normalize-package-data "^2.3.2" | ||
1375 | path-type "^1.0.0" | ||
1376 | |||
1377 | 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.2, readable-stream@^2.3.4: | ||
1378 | version "2.3.6" | ||
1379 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" | ||
1380 | integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== | ||
1381 | dependencies: | ||
1382 | core-util-is "~1.0.0" | ||
1383 | inherits "~2.0.3" | ||
1384 | isarray "~1.0.0" | ||
1385 | process-nextick-args "~2.0.0" | ||
1386 | safe-buffer "~5.1.1" | ||
1387 | string_decoder "~1.1.1" | ||
1388 | util-deprecate "~1.0.1" | ||
1389 | |||
1390 | readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6: | ||
1391 | version "3.3.0" | ||
1392 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.3.0.tgz#cb8011aad002eb717bf040291feba8569c986fb9" | ||
1393 | integrity sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw== | ||
1394 | dependencies: | ||
1395 | inherits "^2.0.3" | ||
1396 | string_decoder "^1.1.1" | ||
1397 | util-deprecate "^1.0.1" | ||
1398 | |||
1399 | record-cache@^1.0.2: | ||
1400 | version "1.1.0" | ||
1401 | resolved "https://registry.yarnpkg.com/record-cache/-/record-cache-1.1.0.tgz#f8a467a691a469584b26e88d36b18afdb3932037" | ||
1402 | integrity sha512-u8rbtLEJV7HRacl/ZYwSBFD8NFyB3PfTTfGLP37IW3hftQCwu6z4Q2RLyxo1YJUNRTEzJfpLpGwVuEYdaIkG9Q== | ||
1403 | |||
1404 | render-media@^3.0.0: | ||
1405 | version "3.1.3" | ||
1406 | resolved "https://registry.yarnpkg.com/render-media/-/render-media-3.1.3.tgz#aa8c8cd3f720049370067180709b551d3c566254" | ||
1407 | integrity sha512-K7ziKKlIcgYpAovRsABDiSaNn7TzDDyyuFGpRwM52cloNcajInB6sCxFPUEzOuTJUeyvKCqT/k5INOjpKLCjhQ== | ||
1408 | dependencies: | ||
1409 | debug "^3.1.0" | ||
1410 | is-ascii "^1.0.0" | ||
1411 | mediasource "^2.1.0" | ||
1412 | stream-to-blob-url "^2.0.0" | ||
1413 | videostream "^2.5.1" | ||
1414 | |||
1415 | require-directory@^2.1.1: | ||
1416 | version "2.1.1" | ||
1417 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" | ||
1418 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= | ||
1419 | |||
1420 | require-main-filename@^1.0.1: | ||
1421 | version "1.0.1" | ||
1422 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" | ||
1423 | integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= | ||
1424 | |||
1425 | resolve@^1.10.0: | ||
1426 | version "1.11.0" | ||
1427 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.0.tgz#4014870ba296176b86343d50b60f3b50609ce232" | ||
1428 | integrity sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw== | ||
1429 | dependencies: | ||
1430 | path-parse "^1.0.6" | ||
1431 | |||
1432 | rimraf@^2.4.2, rimraf@^2.6.1: | ||
1433 | version "2.6.3" | ||
1434 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" | ||
1435 | integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== | ||
1436 | dependencies: | ||
1437 | glob "^7.1.3" | ||
1438 | |||
1439 | run-parallel-limit@^1.0.3: | ||
1440 | version "1.0.5" | ||
1441 | resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.0.5.tgz#c29a4fd17b4df358cb52a8a697811a63c984f1b7" | ||
1442 | integrity sha512-NsY+oDngvrvMxKB3G8ijBzIema6aYbQMD2bHOamvN52BysbIGTnEY2xsNyfrcr9GhY995/t/0nQN3R3oZvaDlg== | ||
1443 | |||
1444 | run-parallel@^1.0.0, run-parallel@^1.1.2, run-parallel@^1.1.6: | ||
1445 | version "1.1.9" | ||
1446 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" | ||
1447 | integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== | ||
1448 | |||
1449 | run-series@^1.0.2: | ||
1450 | version "1.1.8" | ||
1451 | resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36" | ||
1452 | integrity sha512-+GztYEPRpIsQoCSraWHDBs9WVy4eVME16zhOtDB4H9J4xN0XRhknnmLOl+4gRgZtu8dpp9N/utSPjKH/xmDzXg== | ||
1453 | |||
1454 | rusha@^0.8.1: | ||
1455 | version "0.8.13" | ||
1456 | resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.13.tgz#9a084e7b860b17bff3015b92c67a6a336191513a" | ||
1457 | integrity sha1-mghOe4YLF7/zAVuSxnpqM2GRUTo= | ||
1458 | |||
1459 | safe-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: | ||
1460 | version "5.1.2" | ||
1461 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" | ||
1462 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== | ||
1463 | |||
1464 | "safer-buffer@>= 2.1.2 < 3": | ||
1465 | version "2.1.2" | ||
1466 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" | ||
1467 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== | ||
1468 | |||
1469 | sax@1.1.4: | ||
1470 | version "1.1.4" | ||
1471 | resolved "https://registry.yarnpkg.com/sax/-/sax-1.1.4.tgz#74b6d33c9ae1e001510f179a91168588f1aedaa9" | ||
1472 | integrity sha1-dLbTPJrh4AFRDxeakRaFiPGu2qk= | ||
1473 | |||
1474 | sax@>=0.6.0, sax@^1.2.4: | ||
1475 | version "1.2.4" | ||
1476 | resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" | ||
1477 | integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== | ||
1478 | |||
1479 | "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0: | ||
1480 | version "5.7.0" | ||
1481 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" | ||
1482 | integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== | ||
1483 | |||
1484 | semver@~5.1.0: | ||
1485 | version "5.1.1" | ||
1486 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.1.1.tgz#a3292a373e6f3e0798da0b20641b9a9c5bc47e19" | ||
1487 | integrity sha1-oykqNz5vPgeY2gsgZBuanFvEfhk= | ||
1488 | |||
1489 | set-blocking@^2.0.0, set-blocking@~2.0.0: | ||
1490 | version "2.0.0" | ||
1491 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" | ||
1492 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= | ||
1493 | |||
1494 | shebang-command@^1.2.0: | ||
1495 | version "1.2.0" | ||
1496 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" | ||
1497 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= | ||
1498 | dependencies: | ||
1499 | shebang-regex "^1.0.0" | ||
1500 | |||
1501 | shebang-regex@^1.0.0: | ||
1502 | version "1.0.0" | ||
1503 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" | ||
1504 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= | ||
1505 | |||
1506 | signal-exit@^3.0.0: | ||
1507 | version "3.0.2" | ||
1508 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" | ||
1509 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= | ||
1510 | |||
1511 | simple-concat@^1.0.0: | ||
1512 | version "1.0.0" | ||
1513 | resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" | ||
1514 | integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= | ||
1515 | |||
1516 | simple-get@^2.0.0, simple-get@^2.1.0: | ||
1517 | version "2.8.1" | ||
1518 | resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" | ||
1519 | integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw== | ||
1520 | dependencies: | ||
1521 | decompress-response "^3.3.0" | ||
1522 | once "^1.3.1" | ||
1523 | simple-concat "^1.0.0" | ||
1524 | |||
1525 | simple-get@^3.0.0, simple-get@^3.0.1: | ||
1526 | version "3.0.3" | ||
1527 | resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.0.3.tgz#924528ac3f9d7718ce5e9ec1b1a69c0be4d62efa" | ||
1528 | integrity sha512-Wvre/Jq5vgoz31Z9stYWPLn0PqRqmBDpFSdypAnHu5AvRVCYPRYGnvryNLiXu8GOBNDH82J2FRHUGMjjHUpXFw== | ||
1529 | dependencies: | ||
1530 | decompress-response "^3.3.0" | ||
1531 | once "^1.3.1" | ||
1532 | simple-concat "^1.0.0" | ||
1533 | |||
1534 | simple-peer@^9.0.0: | ||
1535 | version "9.3.0" | ||
1536 | resolved "https://registry.yarnpkg.com/simple-peer/-/simple-peer-9.3.0.tgz#85ecb126b23d8730f3904f199db65e84141e0f4e" | ||
1537 | integrity sha512-5dLDfrRomrS2LuZUuH2aO7yTGtHFEl5Eb+8ZzqM0KC0lHcYUyJudUomP9ZY/lPUKBx2broL/Eee9bQ53yycEgQ== | ||
1538 | dependencies: | ||
1539 | debug "^4.0.1" | ||
1540 | get-browser-rtc "^1.0.0" | ||
1541 | inherits "^2.0.1" | ||
1542 | randombytes "^2.0.3" | ||
1543 | readable-stream "^2.3.4" | ||
1544 | |||
1545 | simple-sha1@^2.0.0, simple-sha1@^2.0.8, simple-sha1@^2.1.0: | ||
1546 | version "2.1.2" | ||
1547 | resolved "https://registry.yarnpkg.com/simple-sha1/-/simple-sha1-2.1.2.tgz#de40cbd5aae278fde8e3bb3250a35d74c67326b1" | ||
1548 | integrity sha512-TQl9rm4rdKAVmhO++sXAb8TNN0D6JAD5iyI1mqEPNpxUzTRrtm4aOG1pDf/5W/qCFihiaoK6uuL9rvQz1x1VKw== | ||
1549 | dependencies: | ||
1550 | rusha "^0.8.1" | ||
1551 | |||
1552 | simple-websocket@^7.0.1: | ||
1553 | version "7.2.0" | ||
1554 | resolved "https://registry.yarnpkg.com/simple-websocket/-/simple-websocket-7.2.0.tgz#c3190555d74399372b96b51435f2d8c4b04611df" | ||
1555 | integrity sha512-wdxFg1fHw1yqFKWDcw+yNb4VIYqtl+vknZMlpLhvZSlR6l7/iVuwozqo+Qtl73mB1IH5QnXzonD1S+hAaLNTvQ== | ||
1556 | dependencies: | ||
1557 | debug "^3.1.0" | ||
1558 | inherits "^2.0.1" | ||
1559 | randombytes "^2.0.3" | ||
1560 | readable-stream "^2.0.5" | ||
1561 | ws "^6.0.0" | ||
1562 | |||
1563 | spdx-correct@^3.0.0: | ||
1564 | version "3.1.0" | ||
1565 | resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" | ||
1566 | integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== | ||
1567 | dependencies: | ||
1568 | spdx-expression-parse "^3.0.0" | ||
1569 | spdx-license-ids "^3.0.0" | ||
1570 | |||
1571 | spdx-exceptions@^2.1.0: | ||
1572 | version "2.2.0" | ||
1573 | resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" | ||
1574 | integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== | ||
1575 | |||
1576 | spdx-expression-parse@^3.0.0: | ||
1577 | version "3.0.0" | ||
1578 | resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" | ||
1579 | integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== | ||
1580 | dependencies: | ||
1581 | spdx-exceptions "^2.1.0" | ||
1582 | spdx-license-ids "^3.0.0" | ||
1583 | |||
1584 | spdx-license-ids@^3.0.0: | ||
1585 | version "3.0.4" | ||
1586 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" | ||
1587 | integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA== | ||
1588 | |||
1589 | speedometer@^1.0.0: | ||
1590 | version "1.1.0" | ||
1591 | resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.1.0.tgz#a30b13abda45687a1a76977012c060f2ac8a7934" | ||
1592 | integrity sha512-z/wAiTESw2XVPssY2XRcme4niTc4S5FkkJ4gknudtVoc33Zil8TdTxHy5torRcgqMqksJV2Yz8HQcvtbsnw0mQ== | ||
1593 | |||
1594 | split@^1.0.0: | ||
1595 | version "1.0.1" | ||
1596 | resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" | ||
1597 | integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== | ||
1598 | dependencies: | ||
1599 | through "2" | ||
1600 | |||
1601 | stream-to-blob-url@^2.0.0, stream-to-blob-url@^2.1.0: | ||
1602 | version "2.1.1" | ||
1603 | resolved "https://registry.yarnpkg.com/stream-to-blob-url/-/stream-to-blob-url-2.1.1.tgz#e1ac97f86ca8e9f512329a48e7830ce9a50beef2" | ||
1604 | integrity sha512-DKJPEmCmIZoBfGVle9IhSfERiWaN5cuOtmfPxP2dZbLDRZxkBWZ4QbYxEJOSALk1Kf+WjBgedAMO6qkkf7Lmrg== | ||
1605 | dependencies: | ||
1606 | stream-to-blob "^1.0.0" | ||
1607 | |||
1608 | stream-to-blob@^1.0.0: | ||
1609 | version "1.0.1" | ||
1610 | resolved "https://registry.yarnpkg.com/stream-to-blob/-/stream-to-blob-1.0.1.tgz#2dc1e09b71677a234d00445f8eb7ff70c4fe9948" | ||
1611 | integrity sha512-aRy4neA4rf+qMtLT9fCRLPGWdrsIKtCx4kUdNTIPgPQ2hkHkdxbViVAvABMx9oRM6yCWfngHx6pwXfbYkVuPuw== | ||
1612 | dependencies: | ||
1613 | once "^1.3.3" | ||
1614 | |||
1615 | stream-with-known-length-to-buffer@^1.0.0: | ||
1616 | version "1.0.2" | ||
1617 | resolved "https://registry.yarnpkg.com/stream-with-known-length-to-buffer/-/stream-with-known-length-to-buffer-1.0.2.tgz#b8ea5a92086a1ed5d27fc4c529636682118c945b" | ||
1618 | integrity sha512-UxSISjxmguvfYzZdq6d4XAjc3gAocqTIOS1CjgwkDkkGT/LMTsIYiV8agIw42IHFFHf8k4lPOoroCCf4W9oqzg== | ||
1619 | dependencies: | ||
1620 | once "^1.3.3" | ||
1621 | |||
1622 | string-width@^1.0.1, string-width@^1.0.2: | ||
1623 | version "1.0.2" | ||
1624 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" | ||
1625 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= | ||
1626 | dependencies: | ||
1627 | code-point-at "^1.0.0" | ||
1628 | is-fullwidth-code-point "^1.0.0" | ||
1629 | strip-ansi "^3.0.0" | ||
1630 | |||
1631 | "string-width@^1.0.2 || 2": | ||
1632 | version "2.1.1" | ||
1633 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" | ||
1634 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== | ||
1635 | dependencies: | ||
1636 | is-fullwidth-code-point "^2.0.0" | ||
1637 | strip-ansi "^4.0.0" | ||
1638 | |||
1639 | string2compact@^1.1.1, string2compact@^1.2.5: | ||
1640 | version "1.3.0" | ||
1641 | resolved "https://registry.yarnpkg.com/string2compact/-/string2compact-1.3.0.tgz#22d946127b082d1203c51316af60117a337423c3" | ||
1642 | integrity sha512-004ulKKANDuQilQsNxy2lisrpMG0qUJxBU+2YCEF7KziRyNR0Nredm2qk0f1V82nva59H3y9GWeHXE63HzGRFw== | ||
1643 | dependencies: | ||
1644 | addr-to-ip-port "^1.0.1" | ||
1645 | ipaddr.js "^1.0.1" | ||
1646 | |||
1647 | string_decoder@^1.1.1: | ||
1648 | version "1.2.0" | ||
1649 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" | ||
1650 | integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== | ||
1651 | dependencies: | ||
1652 | safe-buffer "~5.1.0" | ||
1653 | |||
1654 | string_decoder@~1.1.1: | ||
1655 | version "1.1.1" | ||
1656 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" | ||
1657 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== | ||
1658 | dependencies: | ||
1659 | safe-buffer "~5.1.0" | ||
1660 | |||
1661 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: | ||
1662 | version "3.0.1" | ||
1663 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" | ||
1664 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= | ||
1665 | dependencies: | ||
1666 | ansi-regex "^2.0.0" | ||
1667 | |||
1668 | strip-ansi@^4.0.0: | ||
1669 | version "4.0.0" | ||
1670 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" | ||
1671 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= | ||
1672 | dependencies: | ||
1673 | ansi-regex "^3.0.0" | ||
1674 | |||
1675 | strip-bom@^2.0.0: | ||
1676 | version "2.0.0" | ||
1677 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" | ||
1678 | integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= | ||
1679 | dependencies: | ||
1680 | is-utf8 "^0.2.0" | ||
1681 | |||
1682 | strip-eof@^1.0.0: | ||
1683 | version "1.0.0" | ||
1684 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" | ||
1685 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= | ||
1686 | |||
1687 | strip-json-comments@~2.0.1: | ||
1688 | version "2.0.1" | ||
1689 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" | ||
1690 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= | ||
1691 | |||
1692 | tar@^4: | ||
1693 | version "4.4.8" | ||
1694 | resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" | ||
1695 | integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== | ||
1696 | dependencies: | ||
1697 | chownr "^1.1.1" | ||
1698 | fs-minipass "^1.2.5" | ||
1699 | minipass "^2.3.4" | ||
1700 | minizlib "^1.1.1" | ||
1701 | mkdirp "^0.5.0" | ||
1702 | safe-buffer "^5.1.2" | ||
1703 | yallist "^3.0.2" | ||
1704 | |||
1705 | thirty-two@^1.0.1: | ||
1706 | version "1.0.2" | ||
1707 | resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" | ||
1708 | integrity sha1-TKL//AKlEpDSdEueP1V2k8prYno= | ||
1709 | |||
1710 | through@2: | ||
1711 | version "2.3.8" | ||
1712 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" | ||
1713 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= | ||
1714 | |||
1715 | thunky@^0.1.0: | ||
1716 | version "0.1.0" | ||
1717 | resolved "https://registry.yarnpkg.com/thunky/-/thunky-0.1.0.tgz#bf30146824e2b6e67b0f2d7a4ac8beb26908684e" | ||
1718 | integrity sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4= | ||
1719 | |||
1720 | thunky@^1.0.1, thunky@^1.0.2: | ||
1721 | version "1.0.3" | ||
1722 | resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826" | ||
1723 | integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow== | ||
1724 | |||
1725 | to-arraybuffer@^1.0.1: | ||
1726 | version "1.0.1" | ||
1727 | resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" | ||
1728 | integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= | ||
1729 | |||
1730 | torrent-discovery@^9.1.1: | ||
1731 | version "9.1.1" | ||
1732 | resolved "https://registry.yarnpkg.com/torrent-discovery/-/torrent-discovery-9.1.1.tgz#56704e6747b24fe00dbb75b442d202051f78d37d" | ||
1733 | integrity sha512-3mHf+bxVCVLrlkPJdAoMbPMY1hpTZVeWw5hNc2pPFm+HCc2DS0HgVFTBTSWtB8vQPWA1hSEZpqJ+3QfdXxDE1g== | ||
1734 | dependencies: | ||
1735 | bittorrent-dht "^9.0.0" | ||
1736 | bittorrent-tracker "^9.0.0" | ||
1737 | debug "^3.1.0" | ||
1738 | run-parallel "^1.1.2" | ||
1739 | |||
1740 | torrent-piece@^2.0.0: | ||
1741 | version "2.0.0" | ||
1742 | resolved "https://registry.yarnpkg.com/torrent-piece/-/torrent-piece-2.0.0.tgz#6598ae67d93699e887f178db267ba16d89d7ec9b" | ||
1743 | integrity sha512-H/Z/yCuvZJj1vl1IQHI8dvF2QrUuXRJoptT5DW5967/dsLpXlCg+uyhFR5lfNj5mNaYePUbKtnL+qKWZGXv4Nw== | ||
1744 | |||
1745 | typedarray-to-buffer@^3.0.0: | ||
1746 | version "3.1.5" | ||
1747 | resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" | ||
1748 | integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== | ||
1749 | dependencies: | ||
1750 | is-typedarray "^1.0.0" | ||
1751 | |||
1752 | typedarray@^0.0.6: | ||
1753 | version "0.0.6" | ||
1754 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" | ||
1755 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= | ||
1756 | |||
1757 | uint64be@^2.0.2: | ||
1758 | version "2.0.2" | ||
1759 | resolved "https://registry.yarnpkg.com/uint64be/-/uint64be-2.0.2.tgz#ef4a179752fe8f9ddaa29544ecfc13490031e8e5" | ||
1760 | integrity sha512-9QqdvpGQTXgxthP+lY4e/gIBy+RuqcBaC6JVwT5I3bDLgT/btL6twZMR0pI3/Fgah9G/pdwzIprE5gL6v9UvyQ== | ||
1761 | dependencies: | ||
1762 | buffer-alloc "^1.1.0" | ||
1763 | |||
1764 | uniq@^1.0.1: | ||
1765 | version "1.0.1" | ||
1766 | resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" | ||
1767 | integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= | ||
1768 | |||
1769 | unordered-array-remove@^1.0.2: | ||
1770 | version "1.0.2" | ||
1771 | resolved "https://registry.yarnpkg.com/unordered-array-remove/-/unordered-array-remove-1.0.2.tgz#c546e8f88e317a0cf2644c97ecb57dba66d250ef" | ||
1772 | integrity sha1-xUbo+I4xegzyZEyX7LV9umbSUO8= | ||
1773 | |||
1774 | upnp-device-client@^1.0.0: | ||
1775 | version "1.0.2" | ||
1776 | resolved "https://registry.yarnpkg.com/upnp-device-client/-/upnp-device-client-1.0.2.tgz#91f84705f2349bf89082855fff4e3006ac435337" | ||
1777 | integrity sha1-kfhHBfI0m/iQgoVf/04wBqxDUzc= | ||
1778 | dependencies: | ||
1779 | concat-stream "^1.4.8" | ||
1780 | debug "^2.1.3" | ||
1781 | elementtree "~0.1.6" | ||
1782 | network-address "^1.0.0" | ||
1783 | |||
1784 | upnp-mediarenderer-client@^1.2.2: | ||
1785 | version "1.2.4" | ||
1786 | resolved "https://registry.yarnpkg.com/upnp-mediarenderer-client/-/upnp-mediarenderer-client-1.2.4.tgz#0c63a51802082b6b03b596c475cc64fc1e0877c8" | ||
1787 | integrity sha1-DGOlGAIIK2sDtZbEdcxk/B4Id8g= | ||
1788 | dependencies: | ||
1789 | debug "^2.1.3" | ||
1790 | elementtree "^0.1.6" | ||
1791 | upnp-device-client "^1.0.0" | ||
1792 | |||
1793 | url-join@^2.0.5: | ||
1794 | version "2.0.5" | ||
1795 | resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" | ||
1796 | integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= | ||
1797 | |||
1798 | ut_metadata@^3.3.0: | ||
1799 | version "3.3.0" | ||
1800 | resolved "https://registry.yarnpkg.com/ut_metadata/-/ut_metadata-3.3.0.tgz#a0e0e861ebc39ed96e506601d1463ade3b548a7e" | ||
1801 | integrity sha512-IK+ke9yL6a4oPLz/3oSW9TW7m9Wr4RG+5kW5aS2YulzEU1QDGAtago/NnOlno91fo3fSO7mnsqzn3NXNXdv8nA== | ||
1802 | dependencies: | ||
1803 | bencode "^2.0.0" | ||
1804 | bitfield "^2.0.0" | ||
1805 | debug "^3.1.0" | ||
1806 | simple-sha1 "^2.0.0" | ||
1807 | |||
1808 | ut_pex@^1.1.1: | ||
1809 | version "1.2.1" | ||
1810 | resolved "https://registry.yarnpkg.com/ut_pex/-/ut_pex-1.2.1.tgz#472ed0ea5e9bbc9148b833339d56d7b17cf3dad0" | ||
1811 | integrity sha512-ZrxMCbffYtxQDqvREN9kBXK2CB9tPnd5PylHoqQX9ai+3HV9/S39FnA5JnhLOC82dxIQQg0nTN2wmhtAdGNtOA== | ||
1812 | dependencies: | ||
1813 | bencode "^2.0.0" | ||
1814 | compact2string "^1.2.0" | ||
1815 | inherits "^2.0.1" | ||
1816 | string2compact "^1.2.5" | ||
1817 | |||
1818 | utf-8-validate@^5.0.1: | ||
1819 | version "5.0.2" | ||
1820 | resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.2.tgz#63cfbccd85dc1f2b66cf7a1d0eebc08ed056bfb3" | ||
1821 | integrity sha512-SwV++i2gTD5qh2XqaPzBnNX88N6HdyhQrNNRykvcS0QKvItV9u3vPEJr+X5Hhfb1JC0r0e1alL0iB09rY8+nmw== | ||
1822 | dependencies: | ||
1823 | node-gyp-build "~3.7.0" | ||
1824 | |||
1825 | util-deprecate@^1.0.1, util-deprecate@~1.0.1: | ||
1826 | version "1.0.2" | ||
1827 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" | ||
1828 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= | ||
1829 | |||
1830 | validate-npm-package-license@^3.0.1: | ||
1831 | version "3.0.4" | ||
1832 | resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" | ||
1833 | integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== | ||
1834 | dependencies: | ||
1835 | spdx-correct "^3.0.0" | ||
1836 | spdx-expression-parse "^3.0.0" | ||
1837 | |||
1838 | videostream@^2.5.1: | ||
1839 | version "2.6.0" | ||
1840 | resolved "https://registry.yarnpkg.com/videostream/-/videostream-2.6.0.tgz#7f0b2b84bc457c12cfe599aa2345f5cc06241ab6" | ||
1841 | integrity sha512-nSsullx1BYClJxVSt4Fa+Ulsv0Cf7UwaHq+4LQdLkAUdmqNhY1DlGxXDWVY2gui5XV4FvDiSbXmSbGryMrrUCQ== | ||
1842 | dependencies: | ||
1843 | binary-search "^1.3.4" | ||
1844 | inherits "^2.0.1" | ||
1845 | mediasource "^2.2.2" | ||
1846 | mp4-box-encoding "^1.3.0" | ||
1847 | mp4-stream "^2.0.0" | ||
1848 | multistream "^2.0.2" | ||
1849 | pump "^3.0.0" | ||
1850 | range-slice-stream "^2.0.0" | ||
1851 | |||
1852 | vlc-command@^1.0.0: | ||
1853 | version "1.1.2" | ||
1854 | resolved "https://registry.yarnpkg.com/vlc-command/-/vlc-command-1.1.2.tgz#61a9b4249a0001c0bcac8cdaf36d3a8e674cffce" | ||
1855 | integrity sha512-KZ15RTHz96OEiQDA8oNFn1edYDWyKJIWI4gF74Am9woZo5XmVYryk5RYXSwOMvsaAgL5ejICEGCl0suQyDBu+Q== | ||
1856 | dependencies: | ||
1857 | run-parallel "^1.1.6" | ||
1858 | winreg "^1.2.1" | ||
1859 | |||
1860 | webidl-conversions@^4.0.2: | ||
1861 | version "4.0.2" | ||
1862 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" | ||
1863 | integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== | ||
1864 | |||
1865 | webtorrent-cli@^1.12.3: | ||
1866 | version "1.12.3" | ||
1867 | resolved "https://registry.yarnpkg.com/webtorrent-cli/-/webtorrent-cli-1.12.3.tgz#e6a1060cd3f104346da91e67763276ca897f238c" | ||
1868 | integrity sha512-NnBAGkD64CRsl9edM9q0QU+ku6nCX32nM0U+YC8Gs/36c8y+5m9Tya3mWIux3oZKZ54yGiVtnok4tUpqDE5tMA== | ||
1869 | dependencies: | ||
1870 | clivas "^0.2.0" | ||
1871 | create-torrent "^3.23.1" | ||
1872 | dlnacasts "^0.1.0" | ||
1873 | ecstatic "^3.0.0" | ||
1874 | executable "^4.0.0" | ||
1875 | mime "^2.1.0" | ||
1876 | minimist "^1.2.0" | ||
1877 | moment "^2.12.0" | ||
1878 | network-address "^1.1.0" | ||
1879 | open "0.0.5" | ||
1880 | parse-torrent "^6.0.0" | ||
1881 | prettier-bytes "^1.0.3" | ||
1882 | vlc-command "^1.0.0" | ||
1883 | webtorrent "0.x" | ||
1884 | winreg "^1.0.1" | ||
1885 | optionalDependencies: | ||
1886 | airplay-js "^0.3.0" | ||
1887 | chromecasts "^1.5.3" | ||
1888 | nodebmc "0.0.7" | ||
1889 | |||
1890 | webtorrent-hybrid@^2.1.0: | ||
1891 | version "2.1.0" | ||
1892 | resolved "https://registry.yarnpkg.com/webtorrent-hybrid/-/webtorrent-hybrid-2.1.0.tgz#c14d33d6769667d8ae524ca2d9dfdcd18d4cfbf2" | ||
1893 | integrity sha512-S8tUgUbPLwGazPrBMTqjsuxlmhaCZaiC+KlgS7ECRGaHVVZTJjKG2kUw8uf558DdZbsEA3jNxOOsMvXiA62sFw== | ||
1894 | dependencies: | ||
1895 | create-torrent "^3.33.0" | ||
1896 | webtorrent "^0.x" | ||
1897 | webtorrent-cli "^1.12.3" | ||
1898 | wrtc "^0.3.3" | ||
1899 | |||
1900 | webtorrent@0.x, webtorrent@^0.x: | ||
1901 | version "0.103.1" | ||
1902 | resolved "https://registry.yarnpkg.com/webtorrent/-/webtorrent-0.103.1.tgz#18ead369bbcaa60dc8ea138784c33451edd34479" | ||
1903 | integrity sha512-rqMD8sAaPzrUzEpA6gDEOgcN9Xyz4WGrQiHoVY6HlymLoNSkScMnmnEX1bsdMcIU9iOrnUlghDEW9sJ9jYCmwQ== | ||
1904 | dependencies: | ||
1905 | addr-to-ip-port "^1.4.2" | ||
1906 | bitfield "^2.0.0" | ||
1907 | bittorrent-dht "^9.0.0" | ||
1908 | bittorrent-protocol "^3.0.0" | ||
1909 | chunk-store-stream "^3.0.1" | ||
1910 | create-torrent "^3.33.0" | ||
1911 | debug "^4.1.0" | ||
1912 | end-of-stream "^1.1.0" | ||
1913 | fs-chunk-store "^1.6.2" | ||
1914 | immediate-chunk-store "^2.0.0" | ||
1915 | load-ip-set "^2.1.0" | ||
1916 | memory-chunk-store "^1.2.0" | ||
1917 | mime "^2.4.0" | ||
1918 | multistream "^2.0.5" | ||
1919 | package-json-versionify "^1.0.2" | ||
1920 | parse-numeric-range "^0.0.2" | ||
1921 | parse-torrent "^6.1.2" | ||
1922 | pump "^3.0.0" | ||
1923 | random-iterate "^1.0.1" | ||
1924 | randombytes "^2.0.3" | ||
1925 | range-parser "^1.2.0" | ||
1926 | readable-stream "^3.0.6" | ||
1927 | render-media "^3.0.0" | ||
1928 | run-parallel "^1.1.6" | ||
1929 | run-parallel-limit "^1.0.3" | ||
1930 | safe-buffer "^5.0.1" | ||
1931 | simple-concat "^1.0.0" | ||
1932 | simple-get "^3.0.1" | ||
1933 | simple-peer "^9.0.0" | ||
1934 | simple-sha1 "^2.0.8" | ||
1935 | speedometer "^1.0.0" | ||
1936 | stream-to-blob "^1.0.0" | ||
1937 | stream-to-blob-url "^2.1.0" | ||
1938 | stream-with-known-length-to-buffer "^1.0.0" | ||
1939 | torrent-discovery "^9.1.1" | ||
1940 | torrent-piece "^2.0.0" | ||
1941 | uniq "^1.0.1" | ||
1942 | unordered-array-remove "^1.0.2" | ||
1943 | ut_metadata "^3.3.0" | ||
1944 | ut_pex "^1.1.1" | ||
1945 | |||
1946 | which-module@^1.0.0: | ||
1947 | version "1.0.0" | ||
1948 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" | ||
1949 | integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= | ||
1950 | |||
1951 | which@^1.2.14, which@^1.2.9: | ||
1952 | version "1.3.1" | ||
1953 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" | ||
1954 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== | ||
1955 | dependencies: | ||
1956 | isexe "^2.0.0" | ||
1957 | |||
1958 | wide-align@^1.1.0: | ||
1959 | version "1.1.3" | ||
1960 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" | ||
1961 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== | ||
1962 | dependencies: | ||
1963 | string-width "^1.0.2 || 2" | ||
1964 | |||
1965 | winreg@^1.0.1, winreg@^1.2.1: | ||
1966 | version "1.2.4" | ||
1967 | resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b" | ||
1968 | integrity sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs= | ||
1969 | |||
1970 | wrap-ansi@^2.0.0: | ||
1971 | version "2.1.0" | ||
1972 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" | ||
1973 | integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= | ||
1974 | dependencies: | ||
1975 | string-width "^1.0.1" | ||
1976 | strip-ansi "^3.0.1" | ||
1977 | |||
1978 | wrappy@1: | ||
1979 | version "1.0.2" | ||
1980 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" | ||
1981 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= | ||
1982 | |||
1983 | wrtc@^0.3.3: | ||
1984 | version "0.3.7" | ||
1985 | resolved "https://registry.yarnpkg.com/wrtc/-/wrtc-0.3.7.tgz#2279f1cb3a83573e77b3d9b7e720071fab2ae4af" | ||
1986 | integrity sha512-mDFNFqAB+3IYVKlP15vpGD0EhXjsQlj/GLNje4KLpClLSq8pyTG0xqJFoU+Oq43XvDIUMmIJ/r1aNfrjT7KUQw== | ||
1987 | dependencies: | ||
1988 | nan "^2.3.2" | ||
1989 | node-cmake "2.3.2" | ||
1990 | node-pre-gyp "0.11.x" | ||
1991 | optionalDependencies: | ||
1992 | domexception "^1.0.1" | ||
1993 | |||
1994 | ws@^6.0.0: | ||
1995 | version "6.2.1" | ||
1996 | resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" | ||
1997 | integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== | ||
1998 | dependencies: | ||
1999 | async-limiter "~1.0.0" | ||
2000 | |||
2001 | xml2js@^0.4.8: | ||
2002 | version "0.4.19" | ||
2003 | resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" | ||
2004 | integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== | ||
2005 | dependencies: | ||
2006 | sax ">=0.6.0" | ||
2007 | xmlbuilder "~9.0.1" | ||
2008 | |||
2009 | xmlbuilder@0.4.x: | ||
2010 | version "0.4.3" | ||
2011 | resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-0.4.3.tgz#c4614ba74e0ad196e609c9272cd9e1ddb28a8a58" | ||
2012 | integrity sha1-xGFLp04K0ZbmCcknLNnh3bKKilg= | ||
2013 | |||
2014 | xmlbuilder@~9.0.1: | ||
2015 | version "9.0.7" | ||
2016 | resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" | ||
2017 | integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= | ||
2018 | |||
2019 | xmldom@0.1.x: | ||
2020 | version "0.1.27" | ||
2021 | resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" | ||
2022 | integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk= | ||
2023 | |||
2024 | xtend@^4.0.0, xtend@^4.0.1: | ||
2025 | version "4.0.1" | ||
2026 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" | ||
2027 | integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= | ||
2028 | |||
2029 | y18n@^3.2.1: | ||
2030 | version "3.2.1" | ||
2031 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" | ||
2032 | integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= | ||
2033 | |||
2034 | yallist@^3.0.0, yallist@^3.0.2: | ||
2035 | version "3.0.3" | ||
2036 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" | ||
2037 | integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== | ||
2038 | |||
2039 | yargs-parser@^5.0.0: | ||
2040 | version "5.0.0" | ||
2041 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" | ||
2042 | integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= | ||
2043 | dependencies: | ||
2044 | camelcase "^3.0.0" | ||
2045 | |||
2046 | yargs@^7.0.2: | ||
2047 | version "7.1.0" | ||
2048 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" | ||
2049 | integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= | ||
2050 | dependencies: | ||
2051 | camelcase "^3.0.0" | ||
2052 | cliui "^3.2.0" | ||
2053 | decamelize "^1.1.1" | ||
2054 | get-caller-file "^1.0.1" | ||
2055 | os-locale "^1.4.0" | ||
2056 | read-pkg-up "^1.0.1" | ||
2057 | require-directory "^2.1.1" | ||
2058 | require-main-filename "^1.0.1" | ||
2059 | set-blocking "^2.0.0" | ||
2060 | string-width "^1.0.2" | ||
2061 | which-module "^1.0.0" | ||
2062 | y18n "^3.2.1" | ||
2063 | 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 @@ | |||
1 | function isToday (d: Date) { | ||
2 | const today = new Date() | ||
3 | |||
4 | return areDatesEqual(d, today) | ||
5 | } | ||
6 | |||
7 | function isYesterday (d: Date) { | ||
8 | const yesterday = new Date() | ||
9 | yesterday.setDate(yesterday.getDate() - 1) | ||
10 | |||
11 | return areDatesEqual(d, yesterday) | ||
12 | } | ||
13 | |||
14 | function 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 | |||
28 | function isThisMonth (d: Date) { | ||
29 | const thisMonth = new Date().getMonth() | ||
30 | |||
31 | return d.getMonth() === thisMonth | ||
32 | } | ||
33 | |||
34 | function isLastMonth (d: Date) { | ||
35 | const now = new Date() | ||
36 | |||
37 | return getDaysDifferences(now, d) <= 30 | ||
38 | } | ||
39 | |||
40 | function isLastWeek (d: Date) { | ||
41 | const now = new Date() | ||
42 | |||
43 | return getDaysDifferences(now, d) <= 7 | ||
44 | } | ||
45 | |||
46 | // --------------------------------------------------------------------------- | ||
47 | |||
48 | export { | ||
49 | isYesterday, | ||
50 | isThisWeek, | ||
51 | isThisMonth, | ||
52 | isToday, | ||
53 | isLastMonth, | ||
54 | isLastWeek | ||
55 | } | ||
56 | |||
57 | // --------------------------------------------------------------------------- | ||
58 | |||
59 | function areDatesEqual (d1: Date, d2: Date) { | ||
60 | return d1.getFullYear() === d2.getFullYear() && | ||
61 | d1.getMonth() === d2.getMonth() && | ||
62 | d1.getDate() === d2.getDate() | ||
63 | } | ||
64 | |||
65 | function getDaysDifferences (d1: Date, d2: Date) { | ||
66 | return (d1.getTime() - d2.getTime()) / (86400000) | ||
67 | } | ||
diff --git a/shared/extra-utils/miscs/miscs.ts b/shared/extra-utils/miscs/miscs.ts index d1ffb7be4..fb6430e4f 100644 --- a/shared/extra-utils/miscs/miscs.ts +++ b/shared/extra-utils/miscs/miscs.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* tslint:disable:no-unused-expression */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import { isAbsolute, join } from 'path' | 4 | import { basename, isAbsolute, join, resolve } from 'path' |
5 | import * as request from 'supertest' | 5 | import * as request from 'supertest' |
6 | import * as WebTorrent from 'webtorrent' | 6 | import * as WebTorrent from 'webtorrent' |
7 | import { pathExists, readFile } from 'fs-extra' | 7 | import { pathExists, readFile } from 'fs-extra' |
@@ -34,7 +34,11 @@ function webtorrentAdd (torrent: string, refreshWebTorrent = false) { | |||
34 | 34 | ||
35 | function root () { | 35 | function root () { |
36 | // We are in /miscs | 36 | // We are in /miscs |
37 | return join(__dirname, '..', '..', '..') | 37 | let root = join(__dirname, '..', '..', '..') |
38 | |||
39 | if (basename(root) === 'dist') root = resolve(root, '..') | ||
40 | |||
41 | return root | ||
38 | } | 42 | } |
39 | 43 | ||
40 | async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') { | 44 | async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') { |
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 @@ | |||
1 | import { QueryTypes, Sequelize } from 'sequelize' | 1 | import { QueryTypes, Sequelize } from 'sequelize' |
2 | import { ServerInfo } from '../server/servers' | ||
2 | 3 | ||
3 | let sequelizes: { [ id: number ]: Sequelize } = {} | 4 | let sequelizes: { [ id: number ]: Sequelize } = {} |
4 | 5 | ||
5 | function getSequelize (serverNumber: number) { | 6 | function 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 | ||
26 | function setActorField (serverNumber: number, to: string, field: string, value: string) { | 27 | function 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 | ||
34 | function setVideoField (serverNumber: number, uuid: string, field: string, value: string) { | 35 | function 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 | ||
42 | function setPlaylistField (serverNumber: number, uuid: string, field: string, value: string) { | 43 | function 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 | ||
50 | async function countVideoViewsOf (serverNumber: number, uuid: string) { | 51 | async 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 | ||
65 | async function closeAllSequelize (servers: any[]) { | 66 | async 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 | ||
7 | function searchVideo (url: string, search: string) { | 7 | function 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 | |||
30 | function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) { | 32 | function 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, | |||
46 | function searchVideoWithSort (url: string, search: string, sort: string) { | 52 | function 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..2b7965bc2 100644 --- a/shared/extra-utils/server/config.ts +++ b/shared/extra-utils/server/config.ts | |||
@@ -91,13 +91,15 @@ 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, |
97 | '360p': true, | 98 | '360p': true, |
98 | '480p': true, | 99 | '480p': true, |
99 | '720p': false, | 100 | '720p': false, |
100 | '1080p': false | 101 | '1080p': false, |
102 | '2160p': false | ||
101 | }, | 103 | }, |
102 | hls: { | 104 | hls: { |
103 | enabled: false | 105 | enabled: 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 @@ | |||
1 | import * as request from 'supertest' | 1 | import * as request from 'supertest' |
2 | import { ServerInfo } from './servers' | 2 | import { ServerInfo } from './servers' |
3 | import { waitJobs } from './jobs' | 3 | import { waitJobs } from './jobs' |
4 | import { makeGetRequest, makePostBodyRequest } from '..' | 4 | import { makePostBodyRequest } from '../requests/requests' |
5 | 5 | ||
6 | function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) { | 6 | function 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 | |||
42 | function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) { | 46 | function 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 | ||
248 | async function checkDirectoryIsEmpty (server: ServerInfo, directory: string) { | 248 | async 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 | ||
286 | async function waitUntilLog (server: ServerInfo, str: string, count = 1) { | 286 | async 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 | ||
42 | async function checkActorFilesWereRemoved (actorUUID: string, serverNumber: number) { | 42 | async 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..1c39881d6 100644 --- a/shared/extra-utils/users/users.ts +++ b/shared/extra-utils/users/users.ts | |||
@@ -1,10 +1,11 @@ | |||
1 | import * as request from 'supertest' | 1 | import * as request from 'supertest' |
2 | import { makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests' | 2 | import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests' |
3 | 3 | ||
4 | import { UserRole } from '../../index' | 4 | import { UserCreate, UserRole } from '../../index' |
5 | import { NSFWPolicyType } from '../../models/videos/nsfw-policy.type' | 5 | import { NSFWPolicyType } from '../../models/videos/nsfw-policy.type' |
6 | import { ServerInfo, userLogin } from '..' | 6 | import { ServerInfo, userLogin } from '..' |
7 | import { UserAdminFlag } from '../../models/users/user-flag.model' | 7 | import { UserAdminFlag } from '../../models/users/user-flag.model' |
8 | import { UserRegister } from '../../models/users/user-register.model' | ||
8 | 9 | ||
9 | type CreateUserArgs = { url: string, | 10 | type CreateUserArgs = { url: string, |
10 | accessToken: string, | 11 | accessToken: string, |
@@ -70,6 +71,31 @@ function registerUser (url: string, username: string, password: string, specialS | |||
70 | .expect(specialStatus) | 71 | .expect(specialStatus) |
71 | } | 72 | } |
72 | 73 | ||
74 | function registerUserWithChannel (options: { | ||
75 | url: string, | ||
76 | user: { username: string, password: string, displayName?: 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 | if (options.user.displayName) { | ||
88 | Object.assign(body, { displayName: options.user.displayName }) | ||
89 | } | ||
90 | |||
91 | return makePostBodyRequest({ | ||
92 | url: options.url, | ||
93 | path, | ||
94 | fields: body, | ||
95 | statusCodeExpected: 204 | ||
96 | }) | ||
97 | } | ||
98 | |||
73 | function getMyUserInformation (url: string, accessToken: string, specialStatus = 200) { | 99 | function getMyUserInformation (url: string, accessToken: string, specialStatus = 200) { |
74 | const path = '/api/v1/users/me' | 100 | const path = '/api/v1/users/me' |
75 | 101 | ||
@@ -138,12 +164,16 @@ function getUsersList (url: string, accessToken: string) { | |||
138 | function getUsersListPaginationAndSort (url: string, accessToken: string, start: number, count: number, sort: string, search?: string) { | 164 | function getUsersListPaginationAndSort (url: string, accessToken: string, start: number, count: number, sort: string, search?: string) { |
139 | const path = '/api/v1/users' | 165 | const path = '/api/v1/users' |
140 | 166 | ||
167 | const query = { | ||
168 | start, | ||
169 | count, | ||
170 | sort, | ||
171 | search | ||
172 | } | ||
173 | |||
141 | return request(url) | 174 | return request(url) |
142 | .get(path) | 175 | .get(path) |
143 | .query({ start }) | 176 | .query(query) |
144 | .query({ count }) | ||
145 | .query({ sort }) | ||
146 | .query({ search }) | ||
147 | .set('Accept', 'application/json') | 177 | .set('Accept', 'application/json') |
148 | .set('Authorization', 'Bearer ' + accessToken) | 178 | .set('Authorization', 'Bearer ' + accessToken) |
149 | .expect(200) | 179 | .expect(200) |
@@ -293,13 +323,16 @@ function askSendVerifyEmail (url: string, email: string) { | |||
293 | }) | 323 | }) |
294 | } | 324 | } |
295 | 325 | ||
296 | function verifyEmail (url: string, userId: number, verificationString: string, statusCodeExpected = 204) { | 326 | function verifyEmail (url: string, userId: number, verificationString: string, isPendingEmail = false, statusCodeExpected = 204) { |
297 | const path = '/api/v1/users/' + userId + '/verify-email' | 327 | const path = '/api/v1/users/' + userId + '/verify-email' |
298 | 328 | ||
299 | return makePostBodyRequest({ | 329 | return makePostBodyRequest({ |
300 | url, | 330 | url, |
301 | path, | 331 | path, |
302 | fields: { verificationString }, | 332 | fields: { |
333 | verificationString, | ||
334 | isPendingEmail | ||
335 | }, | ||
303 | statusCodeExpected | 336 | statusCodeExpected |
304 | }) | 337 | }) |
305 | } | 338 | } |
@@ -312,6 +345,7 @@ export { | |||
312 | getMyUserInformation, | 345 | getMyUserInformation, |
313 | getMyUserVideoRating, | 346 | getMyUserVideoRating, |
314 | deleteMe, | 347 | deleteMe, |
348 | registerUserWithChannel, | ||
315 | getMyUserVideoQuotaUsed, | 349 | getMyUserVideoQuotaUsed, |
316 | getUsersList, | 350 | getUsersList, |
317 | getUsersListPaginationAndSort, | 351 | 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 @@ | |||
1 | import * as request from 'supertest' | 1 | import * as request from 'supertest' |
2 | import { VideoChannelCreate, VideoChannelUpdate } from '../../models/videos' | 2 | import { VideoChannelCreate, VideoChannelUpdate } from '../../models/videos' |
3 | import { updateAvatarRequest } from '../requests/requests' | 3 | import { makeGetRequest, updateAvatarRequest } from '../requests/requests' |
4 | import { getMyUserInformation, ServerInfo } from '..' | 4 | import { getMyUserInformation, ServerInfo } from '..' |
5 | import { User } from '../..' | 5 | import { 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 | ||
22 | function getAccountVideoChannelsList (url: string, accountName: string, specialStatus = 200) { | 22 | function 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 | ||
32 | function addVideoChannel ( | 46 | function 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 | ||
253 | async function checkPlaylistFilesWereRemoved ( | 253 | async 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..c78563232 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts | |||
@@ -362,6 +362,10 @@ async function uploadVideo (url: string, accessToken: string, videoAttributesArg | |||
362 | .field('privacy', attributes.privacy.toString()) | 362 | .field('privacy', attributes.privacy.toString()) |
363 | .field('channelId', attributes.channelId) | 363 | .field('channelId', attributes.channelId) |
364 | 364 | ||
365 | if (attributes.support !== undefined) { | ||
366 | req.field('support', attributes.support) | ||
367 | } | ||
368 | |||
365 | if (attributes.description !== undefined) { | 369 | if (attributes.description !== undefined) { |
366 | req.field('description', attributes.description) | 370 | req.field('description', attributes.description) |
367 | } | 371 | } |
@@ -524,7 +528,6 @@ async function completeVideoCheck ( | |||
524 | expect(video.nsfw).to.equal(attributes.nsfw) | 528 | expect(video.nsfw).to.equal(attributes.nsfw) |
525 | expect(video.description).to.equal(attributes.description) | 529 | expect(video.description).to.equal(attributes.description) |
526 | expect(video.account.id).to.be.a('number') | 530 | 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) | 531 | expect(video.account.host).to.equal(attributes.account.host) |
529 | expect(video.account.name).to.equal(attributes.account.name) | 532 | expect(video.account.name).to.equal(attributes.account.name) |
530 | expect(video.channel.displayName).to.equal(attributes.channel.displayName) | 533 | expect(video.channel.displayName).to.equal(attributes.channel.displayName) |
@@ -568,8 +571,8 @@ async function completeVideoCheck ( | |||
568 | expect(file).not.to.be.undefined | 571 | expect(file).not.to.be.undefined |
569 | 572 | ||
570 | let extension = extname(attributes.fixture) | 573 | let extension = extname(attributes.fixture) |
571 | // Transcoding enabled on server 2, extension will always be .mp4 | 574 | // Transcoding enabled: extension will always be .mp4 |
572 | if (attributes.account.host === 'localhost:9002') extension = '.mp4' | 575 | if (attributes.files.length > 1) extension = '.mp4' |
573 | 576 | ||
574 | const magnetUri = file.magnetUri | 577 | const magnetUri = file.magnetUri |
575 | expect(file.magnetUri).to.have.lengthOf.above(2) | 578 | 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 | ||
11 | export interface AccountSummary { | 11 | export 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 | ||
3 | export interface Actor { | 3 | export 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..670553d16 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 |
@@ -61,6 +62,7 @@ export interface CustomConfig { | |||
61 | '480p': boolean | 62 | '480p': boolean |
62 | '720p': boolean | 63 | '720p': boolean |
63 | '1080p': boolean | 64 | '1080p': boolean |
65 | '2160p': boolean | ||
64 | } | 66 | } |
65 | hls: { | 67 | hls: { |
66 | enabled: boolean | 68 | enabled: 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..cf9a43a67 --- /dev/null +++ b/shared/models/users/user-register.model.ts | |||
@@ -0,0 +1,12 @@ | |||
1 | export interface UserRegister { | ||
2 | username: string | ||
3 | password: string | ||
4 | email: string | ||
5 | |||
6 | displayName?: string | ||
7 | |||
8 | channel?: { | ||
9 | name: string | ||
10 | displayName: string | ||
11 | } | ||
12 | } | ||
diff --git a/shared/models/users/user.model.ts b/shared/models/users/user.model.ts index 2f6a3c719..b5823b47a 100644 --- a/shared/models/users/user.model.ts +++ b/shared/models/users/user.model.ts | |||
@@ -9,6 +9,7 @@ export interface User { | |||
9 | id: number | 9 | id: number |
10 | username: string | 10 | username: string |
11 | email: string | 11 | email: string |
12 | pendingEmail: string | null | ||
12 | emailVerified: boolean | 13 | emailVerified: boolean |
13 | nsfwPolicy: NSFWPolicyType | 14 | nsfwPolicy: NSFWPolicyType |
14 | 15 | ||
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 @@ | |||
1 | export interface VideoChannelUpdate { | 1 | export 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 | ||
13 | export interface VideoChannelSummary { | 13 | export 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 @@ | |||
1 | import { VideoPlaylistPrivacy } from './video-playlist-privacy.model' | 1 | import { VideoPlaylistPrivacy } from './video-playlist-privacy.model' |
2 | 2 | ||
3 | export interface VideoPlaylistUpdate { | 3 | export 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/shared/models/videos/video.model.ts b/shared/models/videos/video.model.ts index 963268674..0489147e4 100644 --- a/shared/models/videos/video.model.ts +++ b/shared/models/videos/video.model.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { AccountSummary, VideoChannelSummary, VideoResolution, VideoState } from '../../index' | 1 | import { AccountSummary, VideoChannelSummary, VideoResolution, VideoState } from '../../index' |
2 | import { Account } from '../actors' | 2 | import { Account } from '../actors' |
3 | import { Avatar } from '../avatars/avatar.model' | ||
4 | import { VideoChannel } from './channel/video-channel.model' | 3 | import { VideoChannel } from './channel/video-channel.model' |
5 | import { VideoPrivacy } from './video-privacy.enum' | 4 | import { VideoPrivacy } from './video-privacy.enum' |
6 | import { VideoScheduleUpdate } from './video-schedule-update.model' | 5 | import { VideoScheduleUpdate } from './video-schedule-update.model' |
@@ -68,9 +67,9 @@ export interface VideoDetails extends Video { | |||
68 | descriptionPath: string | 67 | descriptionPath: string |
69 | support: string | 68 | support: string |
70 | channel: VideoChannel | 69 | channel: VideoChannel |
70 | account: Account | ||
71 | tags: string[] | 71 | tags: string[] |
72 | files: VideoFile[] | 72 | files: VideoFile[] |
73 | account: Account | ||
74 | commentsEnabled: boolean | 73 | commentsEnabled: boolean |
75 | downloadEnabled: boolean | 74 | downloadEnabled: boolean |
76 | 75 | ||
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml index 0ab0c71c4..0dc50e403 100644 --- a/support/doc/api/openapi.yaml +++ b/support/doc/api/openapi.yaml | |||
@@ -38,7 +38,7 @@ info: | |||
38 | } | 38 | } |
39 | ``` | 39 | ``` |
40 | externalDocs: | 40 | externalDocs: |
41 | url: https://docs.joinpeertube.org/api.html | 41 | url: https://docs.joinpeertube.org/#/api-rest-reference.html |
42 | tags: | 42 | tags: |
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 |
@@ -849,21 +844,8 @@ paths: | |||
849 | commentsEnabled: | 844 | commentsEnabled: |
850 | description: Enable or disable comments for this video | 845 | description: Enable or disable comments for this video |
851 | type: string | 846 | type: string |
852 | scheduleUpdate: &ref_0 | 847 | scheduleUpdate: |
853 | type: object | 848 | $ref: '#/components/schemas/VideoScheduledUpdate' |
854 | properties: | ||
855 | privacy: | ||
856 | type: string | ||
857 | enum: | ||
858 | - Public | ||
859 | - Unlisted | ||
860 | description: Video privacy target | ||
861 | updateAt: | ||
862 | type: string | ||
863 | format: date | ||
864 | description: When to update the video | ||
865 | required: | ||
866 | - updateAt | ||
867 | get: | 849 | get: |
868 | summary: Get a video by its id | 850 | summary: Get a video by its id |
869 | tags: | 851 | tags: |
@@ -876,7 +858,7 @@ paths: | |||
876 | content: | 858 | content: |
877 | application/json: | 859 | application/json: |
878 | schema: | 860 | schema: |
879 | $ref: '#/components/schemas/Video' | 861 | $ref: '#/components/schemas/VideoDetails' |
880 | delete: | 862 | delete: |
881 | summary: Delete a video by its id | 863 | summary: Delete a video by its id |
882 | security: | 864 | security: |
@@ -1025,7 +1007,7 @@ paths: | |||
1025 | description: Video preview file | 1007 | description: Video preview file |
1026 | type: string | 1008 | type: string |
1027 | privacy: | 1009 | privacy: |
1028 | $ref: '#/components/schemas/VideoPrivacy' | 1010 | $ref: '#/components/schemas/VideoPrivacySet' |
1029 | category: | 1011 | category: |
1030 | description: Video category | 1012 | description: Video category |
1031 | type: string | 1013 | type: string |
@@ -1058,7 +1040,8 @@ paths: | |||
1058 | commentsEnabled: | 1040 | commentsEnabled: |
1059 | description: Enable or disable comments for this video | 1041 | description: Enable or disable comments for this video |
1060 | type: string | 1042 | type: string |
1061 | scheduleUpdate: *ref_0 | 1043 | scheduleUpdate: |
1044 | $ref: '#/components/schemas/VideoScheduledUpdate' | ||
1062 | required: | 1045 | required: |
1063 | - videofile | 1046 | - videofile |
1064 | - channelId | 1047 | - channelId |
@@ -1129,7 +1112,7 @@ paths: | |||
1129 | description: Video preview file | 1112 | description: Video preview file |
1130 | type: string | 1113 | type: string |
1131 | privacy: | 1114 | privacy: |
1132 | $ref: '#/components/schemas/VideoPrivacy' | 1115 | $ref: '#/components/schemas/VideoPrivacySet' |
1133 | category: | 1116 | category: |
1134 | description: Video category | 1117 | description: Video category |
1135 | type: string | 1118 | type: string |
@@ -1162,7 +1145,8 @@ paths: | |||
1162 | commentsEnabled: | 1145 | commentsEnabled: |
1163 | description: Enable or disable comments for this video | 1146 | description: Enable or disable comments for this video |
1164 | type: string | 1147 | type: string |
1165 | scheduleUpdate: *ref_0 | 1148 | scheduleUpdate: |
1149 | $ref: '#/components/schemas/VideoScheduledUpdate' | ||
1166 | required: | 1150 | required: |
1167 | - channelId | 1151 | - channelId |
1168 | - name | 1152 | - name |
@@ -1247,6 +1231,58 @@ paths: | |||
1247 | type: array | 1231 | type: array |
1248 | items: | 1232 | items: |
1249 | $ref: '#/components/schemas/VideoBlacklist' | 1233 | $ref: '#/components/schemas/VideoBlacklist' |
1234 | /videos/{id}/captions: | ||
1235 | get: | ||
1236 | summary: Get list of video's captions | ||
1237 | tags: | ||
1238 | - Video Caption | ||
1239 | parameters: | ||
1240 | - $ref: '#/components/parameters/id2' | ||
1241 | responses: | ||
1242 | '200': | ||
1243 | description: successful operation | ||
1244 | content: | ||
1245 | application/json: | ||
1246 | schema: | ||
1247 | type: object | ||
1248 | properties: | ||
1249 | total: | ||
1250 | type: integer | ||
1251 | data: | ||
1252 | type: array | ||
1253 | items: | ||
1254 | $ref: '#/components/schemas/VideoCaption' | ||
1255 | /videos/{id}/captions/{captionLanguage}: | ||
1256 | put: | ||
1257 | summary: Add or replace a video caption | ||
1258 | tags: | ||
1259 | - Video Caption | ||
1260 | parameters: | ||
1261 | - $ref: '#/components/parameters/id2' | ||
1262 | - $ref: '#/components/parameters/captionLanguage' | ||
1263 | requestBody: | ||
1264 | content: | ||
1265 | multipart/form-data: | ||
1266 | schema: | ||
1267 | type: object | ||
1268 | properties: | ||
1269 | captionfile: | ||
1270 | description: The file to upload. | ||
1271 | type: string | ||
1272 | format: binary | ||
1273 | responses: | ||
1274 | '204': | ||
1275 | $ref: '#/paths/~1users~1me/put/responses/204' | ||
1276 | delete: | ||
1277 | summary: Delete a video caption | ||
1278 | tags: | ||
1279 | - Video Caption | ||
1280 | parameters: | ||
1281 | - $ref: '#/components/parameters/id2' | ||
1282 | - $ref: '#/components/parameters/captionLanguage' | ||
1283 | responses: | ||
1284 | '204': | ||
1285 | $ref: '#/paths/~1users~1me/put/responses/204' | ||
1250 | /video-channels: | 1286 | /video-channels: |
1251 | get: | 1287 | get: |
1252 | summary: Get list of video channels | 1288 | summary: Get list of video channels |
@@ -1275,7 +1311,10 @@ paths: | |||
1275 | '204': | 1311 | '204': |
1276 | $ref: '#/paths/~1users~1me/put/responses/204' | 1312 | $ref: '#/paths/~1users~1me/put/responses/204' |
1277 | requestBody: | 1313 | requestBody: |
1278 | $ref: '#/components/requestBodies/VideoChannelInput' | 1314 | content: |
1315 | application/json: | ||
1316 | schema: | ||
1317 | $ref: '#/components/schemas/VideoChannelCreate' | ||
1279 | '/video-channels/{channelHandle}': | 1318 | '/video-channels/{channelHandle}': |
1280 | get: | 1319 | get: |
1281 | summary: Get a video channel by its id | 1320 | summary: Get a video channel by its id |
@@ -1302,7 +1341,10 @@ paths: | |||
1302 | '204': | 1341 | '204': |
1303 | $ref: '#/paths/~1users~1me/put/responses/204' | 1342 | $ref: '#/paths/~1users~1me/put/responses/204' |
1304 | requestBody: | 1343 | requestBody: |
1305 | $ref: '#/components/requestBodies/VideoChannelInput' | 1344 | content: |
1345 | application/json: | ||
1346 | schema: | ||
1347 | $ref: '#/components/schemas/VideoChannelUpdate' | ||
1306 | delete: | 1348 | delete: |
1307 | summary: Delete a video channel by its id | 1349 | summary: Delete a video channel by its id |
1308 | security: | 1350 | security: |
@@ -1318,6 +1360,7 @@ paths: | |||
1318 | get: | 1360 | get: |
1319 | summary: Get videos of a video channel by its id | 1361 | summary: Get videos of a video channel by its id |
1320 | tags: | 1362 | tags: |
1363 | - Video | ||
1321 | - Video Channel | 1364 | - Video Channel |
1322 | parameters: | 1365 | parameters: |
1323 | - $ref: '#/components/parameters/channelHandle' | 1366 | - $ref: '#/components/parameters/channelHandle' |
@@ -1327,7 +1370,7 @@ paths: | |||
1327 | content: | 1370 | content: |
1328 | application/json: | 1371 | application/json: |
1329 | schema: | 1372 | schema: |
1330 | $ref: '#/components/schemas/Video' | 1373 | $ref: '#/components/schemas/VideoListResponse' |
1331 | '/accounts/{name}/video-channels': | 1374 | '/accounts/{name}/video-channels': |
1332 | get: | 1375 | get: |
1333 | summary: Get video channels of an account by its name | 1376 | summary: Get video channels of an account by its name |
@@ -1443,7 +1486,7 @@ paths: | |||
1443 | schema: | 1486 | schema: |
1444 | $ref: '#/components/schemas/CommentThreadPostResponse' | 1487 | $ref: '#/components/schemas/CommentThreadPostResponse' |
1445 | delete: | 1488 | delete: |
1446 | summary: 'Delete a comment in a comment therad by its id, of a video by its id' | 1489 | summary: 'Delete a comment in a comment thread by its id, of a video by its id' |
1447 | security: | 1490 | security: |
1448 | - OAuth2: [] | 1491 | - OAuth2: [] |
1449 | tags: | 1492 | tags: |
@@ -1487,9 +1530,7 @@ paths: | |||
1487 | content: | 1530 | content: |
1488 | application/json: | 1531 | application/json: |
1489 | schema: | 1532 | schema: |
1490 | type: array | 1533 | $ref: '#/components/schemas/VideoListResponse' |
1491 | items: | ||
1492 | $ref: '#/components/schemas/Video' | ||
1493 | servers: | 1534 | servers: |
1494 | - url: 'https://peertube.cpy.re/api/v1' | 1535 | - url: 'https://peertube.cpy.re/api/v1' |
1495 | description: Live Test Server (live data - stable version) | 1536 | description: Live Test Server (live data - stable version) |
@@ -1611,6 +1652,13 @@ components: | |||
1611 | description: The video id or uuid | 1652 | description: The video id or uuid |
1612 | schema: | 1653 | schema: |
1613 | type: string | 1654 | type: string |
1655 | captionLanguage: | ||
1656 | name: captionLanguage | ||
1657 | in: path | ||
1658 | required: true | ||
1659 | description: The caption language | ||
1660 | schema: | ||
1661 | type: string | ||
1614 | channelHandle: | 1662 | channelHandle: |
1615 | name: channelHandle | 1663 | name: channelHandle |
1616 | in: path | 1664 | in: path |
@@ -1722,12 +1770,6 @@ components: | |||
1722 | type: array | 1770 | type: array |
1723 | items: | 1771 | items: |
1724 | type: string | 1772 | type: string |
1725 | requestBodies: | ||
1726 | VideoChannelInput: | ||
1727 | content: | ||
1728 | application/json: | ||
1729 | schema: | ||
1730 | $ref: '#/components/schemas/VideoChannelInput' | ||
1731 | securitySchemes: | 1773 | securitySchemes: |
1732 | OAuth2: | 1774 | OAuth2: |
1733 | description: > | 1775 | description: > |
@@ -1739,7 +1781,7 @@ components: | |||
1739 | 1781 | ||
1740 | - Have an account with sufficient authorization levels | 1782 | - Have an account with sufficient authorization levels |
1741 | 1783 | ||
1742 | - [Generate](https://docs.joinpeertube.org/lang/en/devdocs/rest.html) a | 1784 | - [Generate](https://docs.joinpeertube.org/#/api-rest-getting-started) a |
1743 | Bearer Token | 1785 | Bearer Token |
1744 | 1786 | ||
1745 | - Make Authenticated Requests | 1787 | - Make Authenticated Requests |
@@ -1764,12 +1806,129 @@ components: | |||
1764 | type: string | 1806 | type: string |
1765 | label: | 1807 | label: |
1766 | type: string | 1808 | type: string |
1767 | VideoPrivacy: | 1809 | VideoPrivacySet: |
1768 | type: string | 1810 | type: integer |
1769 | enum: | 1811 | enum: |
1770 | - Public | 1812 | - 1 |
1771 | - Unlisted | 1813 | - 2 |
1772 | - Private | 1814 | - 3 |
1815 | description: 'The video privacy (Public = 1, Unlisted = 2, Private = 3)' | ||
1816 | VideoPrivacyConstant: | ||
1817 | properties: | ||
1818 | id: | ||
1819 | type: integer | ||
1820 | enum: | ||
1821 | - 1 | ||
1822 | - 2 | ||
1823 | - 3 | ||
1824 | label: | ||
1825 | type: string | ||
1826 | VideoStateConstant: | ||
1827 | properties: | ||
1828 | id: | ||
1829 | type: integer | ||
1830 | enum: | ||
1831 | - 1 | ||
1832 | - 2 | ||
1833 | - 3 | ||
1834 | description: 'The video state (Published = 1, to transcode = 2, to import = 3)' | ||
1835 | label: | ||
1836 | type: string | ||
1837 | VideoResolutionConstant: | ||
1838 | properties: | ||
1839 | id: | ||
1840 | type: integer | ||
1841 | description: 'Video resolution (240, 360, 720 ...)' | ||
1842 | label: | ||
1843 | type: string | ||
1844 | VideoScheduledUpdate: | ||
1845 | properties: | ||
1846 | privacy: | ||
1847 | $ref: '#/components/schemas/VideoPrivacySet' | ||
1848 | description: Video privacy target | ||
1849 | updateAt: | ||
1850 | type: string | ||
1851 | format: date | ||
1852 | description: When to update the video | ||
1853 | required: | ||
1854 | - updateAt | ||
1855 | VideoAccountSummary: | ||
1856 | properties: | ||
1857 | id: | ||
1858 | type: number | ||
1859 | name: | ||
1860 | type: string | ||
1861 | displayName: | ||
1862 | type: string | ||
1863 | url: | ||
1864 | type: string | ||
1865 | host: | ||
1866 | type: string | ||
1867 | avatar: | ||
1868 | nullable: true | ||
1869 | $ref: '#/components/schemas/Avatar' | ||
1870 | VideoChannelSummary: | ||
1871 | properties: | ||
1872 | id: | ||
1873 | type: number | ||
1874 | name: | ||
1875 | type: string | ||
1876 | displayName: | ||
1877 | type: string | ||
1878 | url: | ||
1879 | type: string | ||
1880 | host: | ||
1881 | type: string | ||
1882 | avatar: | ||
1883 | nullable: true | ||
1884 | $ref: '#/components/schemas/Avatar' | ||
1885 | PlaylistElement: | ||
1886 | properties: | ||
1887 | position: | ||
1888 | type: number | ||
1889 | startTimestamp: | ||
1890 | type: number | ||
1891 | stopTimestamp: | ||
1892 | type: number | ||
1893 | VideoFile: | ||
1894 | properties: | ||
1895 | magnetUri: | ||
1896 | type: string | ||
1897 | resolution: | ||
1898 | $ref: '#/components/schemas/VideoResolutionConstant' | ||
1899 | size: | ||
1900 | type: number | ||
1901 | description: 'Video file size in bytes' | ||
1902 | torrentUrl: | ||
1903 | type: string | ||
1904 | torrentDownaloadUrl: | ||
1905 | type: string | ||
1906 | fileUrl: | ||
1907 | type: string | ||
1908 | fileDownloadUrl: | ||
1909 | type: string | ||
1910 | fps: | ||
1911 | type: number | ||
1912 | VideoStreamingPlaylists: | ||
1913 | properties: | ||
1914 | id: | ||
1915 | type: number | ||
1916 | type: | ||
1917 | type: number | ||
1918 | enum: | ||
1919 | - 1 | ||
1920 | description: 'Playlist type (HLS = 1)' | ||
1921 | playlistUrl: | ||
1922 | type: string | ||
1923 | segmentsSha256Url: | ||
1924 | type: string | ||
1925 | redundancies: | ||
1926 | type: array | ||
1927 | items: | ||
1928 | type: object | ||
1929 | properties: | ||
1930 | baseUrl: | ||
1931 | type: string | ||
1773 | Video: | 1932 | Video: |
1774 | properties: | 1933 | properties: |
1775 | id: | 1934 | id: |
@@ -1782,6 +1941,8 @@ components: | |||
1782 | type: string | 1941 | type: string |
1783 | updatedAt: | 1942 | updatedAt: |
1784 | type: string | 1943 | type: string |
1944 | originallyPublishedAt: | ||
1945 | type: string | ||
1785 | category: | 1946 | category: |
1786 | $ref: '#/components/schemas/VideoConstantNumber' | 1947 | $ref: '#/components/schemas/VideoConstantNumber' |
1787 | licence: | 1948 | licence: |
@@ -1789,7 +1950,7 @@ components: | |||
1789 | language: | 1950 | language: |
1790 | $ref: '#/components/schemas/VideoConstantString' | 1951 | $ref: '#/components/schemas/VideoConstantString' |
1791 | privacy: | 1952 | privacy: |
1792 | $ref: '#/components/schemas/VideoPrivacy' | 1953 | $ref: '#/components/schemas/VideoPrivacyConstant' |
1793 | description: | 1954 | description: |
1794 | type: string | 1955 | type: string |
1795 | duration: | 1956 | duration: |
@@ -1812,19 +1973,66 @@ components: | |||
1812 | type: number | 1973 | type: number |
1813 | nsfw: | 1974 | nsfw: |
1814 | type: boolean | 1975 | type: boolean |
1976 | waitTranscoding: | ||
1977 | type: boolean | ||
1978 | nullable: true | ||
1979 | state: | ||
1980 | $ref: '#/components/schemas/VideoStateConstant' | ||
1981 | scheduledUpdate: | ||
1982 | nullable: true | ||
1983 | $ref: '#/components/schemas/VideoScheduledUpdate' | ||
1984 | blacklisted: | ||
1985 | nullable: true | ||
1986 | type: boolean | ||
1987 | blacklistedReason: | ||
1988 | nullable: true | ||
1989 | type: string | ||
1815 | account: | 1990 | account: |
1991 | $ref: '#/components/schemas/VideoAccountSummary' | ||
1992 | channel: | ||
1993 | $ref: '#/components/schemas/VideoChannelSummary' | ||
1994 | userHistory: | ||
1995 | nullable: true | ||
1816 | type: object | 1996 | type: object |
1817 | properties: | 1997 | properties: |
1818 | name: | 1998 | currentTime: |
1819 | type: string | 1999 | type: number |
1820 | displayName: | 2000 | playlistElement: |
1821 | type: string | 2001 | nullable: true |
1822 | url: | 2002 | $ref: '#/components/schemas/PlaylistElement' |
2003 | VideoDetails: | ||
2004 | allOf: | ||
2005 | - $ref: '#/components/schemas/Video' | ||
2006 | - type: object | ||
2007 | properties: | ||
2008 | descriptionPath: | ||
1823 | type: string | 2009 | type: string |
1824 | host: | 2010 | support: |
1825 | type: string | 2011 | type: string |
1826 | avatar: | 2012 | channel: |
1827 | $ref: '#/components/schemas/Avatar' | 2013 | $ref: '#/components/schemas/VideoChannel' |
2014 | account: | ||
2015 | $ref: '#/components/schemas/Account' | ||
2016 | tags: | ||
2017 | type: array | ||
2018 | items: | ||
2019 | type: string | ||
2020 | files: | ||
2021 | type: array | ||
2022 | items: | ||
2023 | $ref: '#/components/schemas/VideoFile' | ||
2024 | commentsEnabled: | ||
2025 | type: boolean | ||
2026 | downloadEnabled: | ||
2027 | type: boolean | ||
2028 | trackerUrls: | ||
2029 | type: array | ||
2030 | items: | ||
2031 | type: string | ||
2032 | streamingPlaylists: | ||
2033 | type: array | ||
2034 | items: | ||
2035 | $ref: '#/components/schemas/VideoStreamingPlaylists' | ||
1828 | VideoAbuse: | 2036 | VideoAbuse: |
1829 | properties: | 2037 | properties: |
1830 | id: | 2038 | id: |
@@ -1917,6 +2125,12 @@ components: | |||
1917 | type: array | 2125 | type: array |
1918 | items: | 2126 | items: |
1919 | $ref: '#/components/schemas/VideoCommentThreadTree' | 2127 | $ref: '#/components/schemas/VideoCommentThreadTree' |
2128 | VideoCaption: | ||
2129 | properties: | ||
2130 | language: | ||
2131 | $ref: '#/components/schemas/VideoConstantString' | ||
2132 | captionPath: | ||
2133 | type: string | ||
1920 | Avatar: | 2134 | Avatar: |
1921 | properties: | 2135 | properties: |
1922 | path: | 2136 | path: |
@@ -1966,6 +2180,13 @@ components: | |||
1966 | autoPlayVideo: | 2180 | autoPlayVideo: |
1967 | type: boolean | 2181 | type: boolean |
1968 | role: | 2182 | role: |
2183 | type: integer | ||
2184 | enum: | ||
2185 | - 0 | ||
2186 | - 1 | ||
2187 | - 2 | ||
2188 | description: 'The user role (Admin = 0, Moderator = 1, User = 2)' | ||
2189 | roleLabel: | ||
1969 | type: string | 2190 | type: string |
1970 | enum: | 2191 | enum: |
1971 | - User | 2192 | - User |
@@ -2096,6 +2317,14 @@ components: | |||
2096 | properties: | 2317 | properties: |
2097 | comment: | 2318 | comment: |
2098 | $ref: '#/components/schemas/VideoComment' | 2319 | $ref: '#/components/schemas/VideoComment' |
2320 | VideoListResponse: | ||
2321 | properties: | ||
2322 | total: | ||
2323 | type: number | ||
2324 | data: | ||
2325 | type: array | ||
2326 | items: | ||
2327 | $ref: '#/components/schemas/Video' | ||
2099 | AddUser: | 2328 | AddUser: |
2100 | properties: | 2329 | properties: |
2101 | username: | 2330 | username: |
@@ -2115,12 +2344,11 @@ components: | |||
2115 | description: 'The user daily video quota ' | 2344 | description: 'The user daily video quota ' |
2116 | role: | 2345 | role: |
2117 | type: integer | 2346 | type: integer |
2118 | format: int32 | ||
2119 | enum: | 2347 | enum: |
2120 | - 0 | 2348 | - 0 |
2121 | - 1 | 2349 | - 1 |
2122 | - 2 | 2350 | - 2 |
2123 | description: 'The user role ' | 2351 | description: 'The user role (Admin = 0, Moderator = 1, User = 2)' |
2124 | required: | 2352 | required: |
2125 | - username | 2353 | - username |
2126 | - password | 2354 | - password |
@@ -2143,8 +2371,12 @@ components: | |||
2143 | type: string | 2371 | type: string |
2144 | description: 'The updated daily video quota of the user ' | 2372 | description: 'The updated daily video quota of the user ' |
2145 | role: | 2373 | role: |
2146 | type: string | 2374 | type: integer |
2147 | description: 'The updated role of the user ' | 2375 | enum: |
2376 | - 0 | ||
2377 | - 1 | ||
2378 | - 2 | ||
2379 | description: 'The user role (Admin = 0, Moderator = 1, User = 2)' | ||
2148 | required: | 2380 | required: |
2149 | - id | 2381 | - id |
2150 | 2382 | ||
@@ -2202,14 +2434,45 @@ components: | |||
2202 | email: | 2434 | email: |
2203 | type: string | 2435 | type: string |
2204 | description: 'The email of the user ' | 2436 | description: 'The email of the user ' |
2437 | displayName: | ||
2438 | type: string | ||
2439 | description: 'The user display name' | ||
2440 | channel: | ||
2441 | type: object | ||
2442 | properties: | ||
2443 | name: | ||
2444 | type: string | ||
2445 | description: 'The default channel name' | ||
2446 | displayName: | ||
2447 | type: string | ||
2448 | description: 'The default channel display name' | ||
2449 | |||
2205 | required: | 2450 | required: |
2206 | - username | 2451 | - username |
2207 | - password | 2452 | - password |
2208 | 2453 | ||
2209 | VideoChannelInput: | 2454 | VideoChannelCreate: |
2210 | properties: | 2455 | properties: |
2211 | name: | 2456 | name: |
2212 | type: string | 2457 | type: string |
2458 | displayName: | ||
2459 | type: string | ||
2460 | description: | ||
2461 | type: string | ||
2462 | support: | ||
2463 | type: string | ||
2464 | required: | ||
2465 | - name | ||
2466 | - displayName | ||
2467 | VideoChannelUpdate: | ||
2468 | properties: | ||
2469 | displayName: | ||
2470 | type: string | ||
2213 | description: | 2471 | description: |
2214 | type: string | 2472 | type: string |
2473 | support: | ||
2474 | type: string | ||
2475 | bulkVideosSupportUpdate: | ||
2476 | type: boolean | ||
2477 | description: 'Update all videos support field of this channel' | ||
2215 | 2478 | ||
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/dependencies.md b/support/doc/dependencies.md index 77cec3ba3..1b27abaa7 100644 --- a/support/doc/dependencies.md +++ b/support/doc/dependencies.md | |||
@@ -26,7 +26,7 @@ | |||
26 | 26 | ||
27 | 3. Install certbot (choose instructions for nginx and your distribution) : | 27 | 3. Install certbot (choose instructions for nginx and your distribution) : |
28 | [https://certbot.eff.org/all-instructions](https://certbot.eff.org/all-instructions) | 28 | [https://certbot.eff.org/all-instructions](https://certbot.eff.org/all-instructions) |
29 | 4. Install NodeJS 8.x (current LTS): | 29 | 4. Install NodeJS 8.x: |
30 | [https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions](https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions) | 30 | [https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions](https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions) |
31 | 5. Install yarn, and be sure to have [a recent version](https://github.com/yarnpkg/yarn/releases/latest): | 31 | 5. Install yarn, and be sure to have [a recent version](https://github.com/yarnpkg/yarn/releases/latest): |
32 | [https://yarnpkg.com/en/docs/install#linux-tab](https://yarnpkg.com/en/docs/install#linux-tab) | 32 | [https://yarnpkg.com/en/docs/install#linux-tab](https://yarnpkg.com/en/docs/install#linux-tab) |
@@ -56,7 +56,7 @@ $ sudo systemctl start redis postgresql | |||
56 | 1. Run: | 56 | 1. Run: |
57 | 57 | ||
58 | ``` | 58 | ``` |
59 | $ sudo pacman -S nodejs yarn ffmpeg postgresql openssl redis git wget unzip python2 base-devel npm nginx | 59 | $ sudo pacman -S nodejs-lts-dubnium yarn ffmpeg postgresql openssl redis git wget unzip python2 base-devel npm nginx |
60 | ``` | 60 | ``` |
61 | 61 | ||
62 | Now that dependencies are installed, before running PeerTube you should start PostgreSQL and Redis: | 62 | Now that dependencies are installed, before running PeerTube you should start PostgreSQL and Redis: |
@@ -66,7 +66,7 @@ $ sudo systemctl start redis postgresql | |||
66 | 66 | ||
67 | ## CentOS 7 | 67 | ## CentOS 7 |
68 | 68 | ||
69 | 1. Install NodeJS 8.x (current LTS): | 69 | 1. Install NodeJS 8.x: |
70 | [https://nodejs.org/en/download/package-manager/#enterprise-linux-and-fedora](https://nodejs.org/en/download/package-manager/#enterprise-linux-and-fedora) | 70 | [https://nodejs.org/en/download/package-manager/#enterprise-linux-and-fedora](https://nodejs.org/en/download/package-manager/#enterprise-linux-and-fedora) |
71 | 2. Install yarn: | 71 | 2. Install yarn: |
72 | [https://yarnpkg.com/en/docs/install](https://yarnpkg.com/en/docs/install) | 72 | [https://yarnpkg.com/en/docs/install](https://yarnpkg.com/en/docs/install) |
@@ -114,7 +114,7 @@ su my-peertube-user | |||
114 | ``` | 114 | ``` |
115 | 2. (Optional) Install certbot (choose instructions for nginx and your distribution) : | 115 | 2. (Optional) Install certbot (choose instructions for nginx and your distribution) : |
116 | [https://certbot.eff.org/all-instructions](https://certbot.eff.org/all-instructions) | 116 | [https://certbot.eff.org/all-instructions](https://certbot.eff.org/all-instructions) |
117 | 3. Install NodeJS 8.x (current LTS): | 117 | 3. Install NodeJS 8.x: |
118 | [https://nodejs.org/en/download/package-manager/#enterprise-linux-and-fedora](https://nodejs.org/en/download/package-manager/#enterprise-linux-and-fedora) | 118 | [https://nodejs.org/en/download/package-manager/#enterprise-linux-and-fedora](https://nodejs.org/en/download/package-manager/#enterprise-linux-and-fedora) |
119 | 4. Install yarn: | 119 | 4. Install yarn: |
120 | [https://yarnpkg.com/en/docs/install](https://yarnpkg.com/en/docs/install) | 120 | [https://yarnpkg.com/en/docs/install](https://yarnpkg.com/en/docs/install) |
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 | |||
3 | The 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 | |||
19 | The client files are in the `client` directory. The Webpack 2 configurations files are in `client/config` and the source files in `client/src`. | ||
20 | The 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. | ||
21 | Here 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 | |||
36 | Details 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 | |||
54 | Uses [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 | |||
58 | In 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. | ||
59 | If 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 | |||
67 | The 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="<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>"><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)<div><br></div></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"><div>Page Not Found</div></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"><div>My Account</div></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 | |||
3 | The 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 | |||
19 | The server main file is [server.ts](/server.ts). | ||
20 | The server modules description are in the [package.json](/package.json) at the project root. | ||
21 | All 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 | |||
38 | Uses [JavaScript Standard Style](http://standardjs.com/). | ||
39 | |||
40 | ## Architecture | ||
41 | |||
42 | The 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 | |||
47 | A 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 | |||
51 | When a user uploads a video, the REST API creates the torrent file and then adds it to its database. | ||
52 | |||
53 | If 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 | |||
57 | The server entrypoint is [server.ts](/server.ts). Looking at this file is a good start. | ||
58 | Then 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 | ||
207 | Alternatively you can set the environment variable `PT_INITIAL_ROOT_PASSWORD`, | ||
208 | to your own administrator password, although it must be 6 characters or more. | ||
209 | |||
207 | ### What now? | 210 | ### What now? |
208 | 211 | ||
209 | Now your instance is up you can: | 212 | Now your instance is up you can: |
diff --git a/support/doc/tools.md b/support/doc/tools.md index 086cd5cff..ba6e2b12d 100644 --- a/support/doc/tools.md +++ b/support/doc/tools.md | |||
@@ -35,7 +35,8 @@ You need to follow all the following steps even if you are on a PeerTube server | |||
35 | 35 | ||
36 | ### Dependencies | 36 | ### Dependencies |
37 | 37 | ||
38 | Install the [PeerTube dependencies](dependencies.md). | 38 | Install the [PeerTube dependencies](dependencies.md) except PostgreSQL and Redis. |
39 | PeerTube only supports NodeJS 8.x or 10.x. | ||
39 | 40 | ||
40 | ### Installation | 41 | ### Installation |
41 | 42 | ||
@@ -44,18 +45,14 @@ Clone the PeerTube repo to get the latest version (even if you are on your PeerT | |||
44 | ``` | 45 | ``` |
45 | $ git clone https://github.com/Chocobozzz/PeerTube.git | 46 | $ git clone https://github.com/Chocobozzz/PeerTube.git |
46 | $ CLONE="$(pwd)/PeerTube" | 47 | $ CLONE="$(pwd)/PeerTube" |
47 | ``` | ||
48 | |||
49 | Run ``yarn install --pure-lockfile`` | ||
50 | ``` | ||
51 | $ cd ${CLONE} | 48 | $ cd ${CLONE} |
52 | $ yarn install --pure-lockfile | ||
53 | ``` | 49 | ``` |
54 | 50 | ||
55 | Build server tools: | 51 | Install dependencies and build CLI tools: |
52 | |||
56 | ``` | 53 | ``` |
57 | $ cd ${CLONE} | 54 | $ NOCLIENT=1 yarn install --pure-lockfile |
58 | $ npm run build:server | 55 | $ npm run setup:cli |
59 | ``` | 56 | ``` |
60 | 57 | ||
61 | ### CLI wrapper | 58 | ### 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 | |||
5 | PEERTUBE_WEBSERVER_HTTPS=true | 5 | PEERTUBE_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: |
8 | PEERTUBE_TRUST_PROXY=["127.0.0.1"] | 8 | PEERTUBE_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= |
12 | PEERTUBE_SMTP_HOSTNAME=postfix | 11 | PEERTUBE_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 | ||
110 | instance: | 113 | instance: |
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 | |||
76 | networks: | ||
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", |
@@ -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 | ||
380 | JSONStream@^1.3.4, JSONStream@^1.3.5: | 401 | abbrev@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 | |||
388 | abbrev@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 | ||
409 | accepts@~1.3.4, accepts@~1.3.5: | 422 | accepts@~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 | ||
417 | acorn-jsx@^3.0.0: | 430 | acorn-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 | ||
449 | agent-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 | |||
456 | agentkeepalive@^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 | |||
463 | ajv-keywords@^1.0.0: | 462 | ajv-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 | ||
517 | ansi-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 | |||
518 | ansi-styles@^2.2.1: | 522 | ansi-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 | ||
523 | ansi-styles@^3.2.1: | 527 | ansi-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 | ||
530 | ansicolors@~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 | |||
535 | ansistyles@~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 | |||
540 | any-observable@^0.3.0: | 534 | any-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 | ||
568 | application-config-path@^0.1.0: | 562 | aproba@^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 | |||
573 | application-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 | |||
581 | aproba@^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 | |||
591 | archy@~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 | |||
596 | are-we-there-yet@~1.1.2: | 567 | are-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 | ||
668 | asap@^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 | |||
673 | asn1@~0.2.3: | 639 | asn1@~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 | ||
700 | async-each@^1.0.1: | 666 | async-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 | ||
705 | async-limiter@~1.0.0: | 671 | async-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 | ||
722 | async@>=0.2.9, async@^2.0.0, async@^2.6.1: | 688 | async@>=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 | |||
693 | async@^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 | ||
759 | babel-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 | |||
768 | backo2@1.0.2: | 730 | backo2@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 | ||
820 | bcrypt@3.0.5: | 782 | bcrypt@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 | ||
828 | bencode@^2.0.0: | 790 | bencode@^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 | ||
842 | bin-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 | |||
853 | binary-extensions@^1.0.0: | 804 | binary-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 | ||
863 | bindings@^1.3.0, bindings@^1.5.0: | 814 | bindings@^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 | ||
870 | bindings@~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 | |||
875 | bindings@~1.3.0: | 821 | bindings@~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 | ||
940 | bittorrent-tracker@^9.0.0: | 886 | bittorrent-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 | ||
1004 | block-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 | |||
1011 | bluebird@3.5.0: | 948 | bluebird@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 | ||
1021 | bluebird@^3.0.5, bluebird@^3.5.0, bluebird@^3.5.1, bluebird@^3.5.3: | 958 | bluebird@^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 | ||
1026 | bn.js@=2.0.4: | 963 | bn.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 | ||
1041 | body-parser@1.18.3, body-parser@^1.12.4: | 978 | body-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 | ||
1057 | boxen@^1.2.1: | 994 | boxen@^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 | ||
1169 | builtins@^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 | |||
1174 | bull@^3.4.2: | 1106 | bull@^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 | ||
1198 | byline@^5.0.0: | 1130 | bytes@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 | |||
1203 | byte-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 | |||
1208 | bytes@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 | |||
1213 | bytes@^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 | ||
1218 | cacache@^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 | |||
1238 | cache-base@^1.0.1: | 1135 | cache-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 | ||
1253 | call-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 | |||
1258 | call-me-maybe@^1.0.1: | 1150 | call-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 | ||
1304 | camelcase@^5.0.0: | 1196 | camelcase@^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 | ||
1309 | camelize@1.0.0: | 1201 | camelize@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 | ||
1324 | chai-json-schema@^1.5.0: | 1216 | chai-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 | ||
1332 | chai-xml@^0.3.2: | 1224 | chai-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 | ||
1371 | chalk@^2.0.1, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: | 1263 | chalk@^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 | ||
1395 | chokidar@^2.1.0: | 1287 | chokidar@^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 | ||
1341 | circular-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 | |||
1449 | class-utils@^0.3.5: | 1346 | class-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 | ||
1464 | cli-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 | |||
1472 | cli-cursor@^1.0.1: | 1361 | cli-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,23 +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 | ||
1486 | cli-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 | |||
1496 | cli-table@^0.3.1: | ||
1497 | version "0.3.1" | ||
1498 | resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" | ||
1499 | integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= | ||
1500 | dependencies: | ||
1501 | colors "1.0.3" | ||
1502 | |||
1503 | cli-truncate@^0.2.1: | 1375 | cli-truncate@^0.2.1: |
1504 | version "0.2.1" | 1376 | version "0.2.1" |
1505 | resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" | 1377 | resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" |
@@ -1522,10 +1394,14 @@ cliui@^4.0.0: | |||
1522 | strip-ansi "^4.0.0" | 1394 | strip-ansi "^4.0.0" |
1523 | wrap-ansi "^2.0.0" | 1395 | wrap-ansi "^2.0.0" |
1524 | 1396 | ||
1525 | clone@^1.0.2: | 1397 | cliui@^5.0.0: |
1526 | version "1.0.4" | 1398 | version "5.0.0" |
1527 | resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" | 1399 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" |
1528 | integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= | 1400 | integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== |
1401 | dependencies: | ||
1402 | string-width "^3.1.0" | ||
1403 | strip-ansi "^5.2.0" | ||
1404 | wrap-ansi "^5.1.0" | ||
1529 | 1405 | ||
1530 | closest-to@~2.0.0: | 1406 | closest-to@~2.0.0: |
1531 | version "2.0.0" | 1407 | version "2.0.0" |
@@ -1545,14 +1421,6 @@ cluster-key-slot@^1.0.6: | |||
1545 | resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.0.12.tgz#d5deff2a520717bc98313979b687309b2d368e29" | 1421 | resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.0.12.tgz#d5deff2a520717bc98313979b687309b2d368e29" |
1546 | integrity sha512-21O0kGmvED5OJ7ZTdqQ5lQQ+sjuez33R+d35jZKLwqUb5mqcPHUsxOSzj61+LHVtxGZd1kShbQM3MjB/gBJkVg== | 1422 | integrity sha512-21O0kGmvED5OJ7ZTdqQ5lQQ+sjuez33R+d35jZKLwqUb5mqcPHUsxOSzj61+LHVtxGZd1kShbQM3MjB/gBJkVg== |
1547 | 1423 | ||
1548 | cmd-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 | |||
1556 | co-bluebird@^1.1.0: | 1424 | co-bluebird@^1.1.0: |
1557 | version "1.1.0" | 1425 | version "1.1.0" |
1558 | resolved "https://registry.yarnpkg.com/co-bluebird/-/co-bluebird-1.1.0.tgz#c8b9f3a9320a7ed30987dcca1a5c3cff59655c7c" | 1426 | resolved "https://registry.yarnpkg.com/co-bluebird/-/co-bluebird-1.1.0.tgz#c8b9f3a9320a7ed30987dcca1a5c3cff59655c7c" |
@@ -1617,10 +1485,10 @@ color@3.0.x: | |||
1617 | color-convert "^1.9.1" | 1485 | color-convert "^1.9.1" |
1618 | color-string "^1.5.2" | 1486 | color-string "^1.5.2" |
1619 | 1487 | ||
1620 | color@^3.1.0: | 1488 | color@^3.1.1: |
1621 | version "3.1.0" | 1489 | version "3.1.2" |
1622 | resolved "https://registry.yarnpkg.com/color/-/color-3.1.0.tgz#d8e9fb096732875774c84bf922815df0308d0ffc" | 1490 | resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" |
1623 | integrity sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg== | 1491 | integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg== |
1624 | dependencies: | 1492 | dependencies: |
1625 | color-convert "^1.9.1" | 1493 | color-convert "^1.9.1" |
1626 | color-string "^1.5.2" | 1494 | color-string "^1.5.2" |
@@ -1630,7 +1498,7 @@ colornames@^1.1.1: | |||
1630 | resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96" | 1498 | resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96" |
1631 | integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y= | 1499 | integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y= |
1632 | 1500 | ||
1633 | colors@1.0.3, colors@1.0.x: | 1501 | colors@1.0.x: |
1634 | version "1.0.3" | 1502 | version "1.0.3" |
1635 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" | 1503 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" |
1636 | integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= | 1504 | integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= |
@@ -1641,25 +1509,17 @@ colors@^1.1.2, colors@^1.2.1: | |||
1641 | integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== | 1509 | integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== |
1642 | 1510 | ||
1643 | colorspace@1.1.x: | 1511 | colorspace@1.1.x: |
1644 | version "1.1.1" | 1512 | version "1.1.2" |
1645 | resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.1.tgz#9ac2491e1bc6f8fb690e2176814f8d091636d972" | 1513 | resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5" |
1646 | integrity sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw== | 1514 | integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ== |
1647 | dependencies: | 1515 | dependencies: |
1648 | color "3.0.x" | 1516 | color "3.0.x" |
1649 | text-hex "1.0.x" | 1517 | text-hex "1.0.x" |
1650 | 1518 | ||
1651 | columnify@~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 | |||
1659 | combined-stream@^1.0.6, combined-stream@~1.0.6: | 1519 | combined-stream@^1.0.6, combined-stream@~1.0.6: |
1660 | version "1.0.7" | 1520 | version "1.0.8" |
1661 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" | 1521 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" |
1662 | integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== | 1522 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== |
1663 | dependencies: | 1523 | dependencies: |
1664 | delayed-stream "~1.0.0" | 1524 | delayed-stream "~1.0.0" |
1665 | 1525 | ||
@@ -1671,9 +1531,9 @@ commander@2.9.0: | |||
1671 | graceful-readlink ">= 1.0.0" | 1531 | graceful-readlink ">= 1.0.0" |
1672 | 1532 | ||
1673 | commander@^2.12.1, commander@^2.13.0, commander@^2.14.1, commander@^2.7.1, commander@^2.8.1, commander@^2.9.0: | 1533 | commander@^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" | 1534 | version "2.20.0" |
1675 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" | 1535 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" |
1676 | integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== | 1536 | integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== |
1677 | 1537 | ||
1678 | compact2string@^1.2.0: | 1538 | compact2string@^1.2.0: |
1679 | version "1.4.1" | 1539 | version "1.4.1" |
@@ -1692,11 +1552,16 @@ component-emitter@1.1.2: | |||
1692 | resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" | 1552 | resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.1.2.tgz#296594f2753daa63996d2af08d15a95116c9aec3" |
1693 | integrity sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM= | 1553 | integrity sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM= |
1694 | 1554 | ||
1695 | component-emitter@1.2.1, component-emitter@^1.2.0, component-emitter@^1.2.1: | 1555 | component-emitter@1.2.1: |
1696 | version "1.2.1" | 1556 | version "1.2.1" |
1697 | resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" | 1557 | resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" |
1698 | integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= | 1558 | integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= |
1699 | 1559 | ||
1560 | component-emitter@^1.2.0, component-emitter@^1.2.1: | ||
1561 | version "1.3.0" | ||
1562 | resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" | ||
1563 | integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== | ||
1564 | |||
1700 | component-inherit@0.0.3: | 1565 | component-inherit@0.0.3: |
1701 | version "0.0.3" | 1566 | version "0.0.3" |
1702 | resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" | 1567 | resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" |
@@ -1707,7 +1572,7 @@ concat-map@0.0.1: | |||
1707 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" | 1572 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" |
1708 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= | 1573 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= |
1709 | 1574 | ||
1710 | concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.2: | 1575 | concat-stream@^1.4.6, concat-stream@^1.5.2: |
1711 | version "1.6.2" | 1576 | version "1.6.2" |
1712 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" | 1577 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" |
1713 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== | 1578 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== |
@@ -1717,7 +1582,7 @@ concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.2: | |||
1717 | readable-stream "^2.2.2" | 1582 | readable-stream "^2.2.2" |
1718 | typedarray "^0.0.6" | 1583 | typedarray "^0.0.6" |
1719 | 1584 | ||
1720 | concurrently@^4.0.1: | 1585 | concurrently@^4.1.0: |
1721 | version "4.1.0" | 1586 | version "4.1.0" |
1722 | resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-4.1.0.tgz#17fdf067da71210685d9ea554423ef239da30d33" | 1587 | resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-4.1.0.tgz#17fdf067da71210685d9ea554423ef239da30d33" |
1723 | integrity sha512-pwzXCE7qtOB346LyO9eFWpkFJVO3JQZ/qU/feGeaAHiX1M3Rw3zgXKc5cZ8vSH5DGygkjzLFDzA/pwoQDkRNGg== | 1588 | integrity sha512-pwzXCE7qtOB346LyO9eFWpkFJVO3JQZ/qU/feGeaAHiX1M3Rw3zgXKc5cZ8vSH5DGygkjzLFDzA/pwoQDkRNGg== |
@@ -1732,18 +1597,10 @@ concurrently@^4.0.1: | |||
1732 | tree-kill "^1.1.0" | 1597 | tree-kill "^1.1.0" |
1733 | yargs "^12.0.1" | 1598 | yargs "^12.0.1" |
1734 | 1599 | ||
1735 | config-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 | |||
1743 | config@^3.0.0: | 1600 | config@^3.0.0: |
1744 | version "3.0.1" | 1601 | version "3.1.0" |
1745 | resolved "https://registry.yarnpkg.com/config/-/config-3.0.1.tgz#c3118e2eb45fdfd135277339f87e2492559cb147" | 1602 | resolved "https://registry.yarnpkg.com/config/-/config-3.1.0.tgz#c7d49c4171e8f6cb61c1d69e22647ffd60492548" |
1746 | integrity sha512-TBNrrk2b6AybUohqXw2AydglFBL9b/+1GG93Di6Fm6x1SyVJ5PYgo+mqY2X0KpU9m0PJDSbFaC5H95utSphtLw== | 1603 | integrity sha512-t6oDeNQbsIWa+D/KF4959TANzjSHLv1BA/hvL8tHEA3OUSWgBXELKaONSI6nr9oanbKs0DXonjOWLcrtZ3yTAA== |
1747 | dependencies: | 1604 | dependencies: |
1748 | json5 "^1.0.1" | 1605 | json5 "^1.0.1" |
1749 | 1606 | ||
@@ -1759,7 +1616,7 @@ configstore@^3.0.0: | |||
1759 | write-file-atomic "^2.0.0" | 1616 | write-file-atomic "^2.0.0" |
1760 | xdg-basedir "^3.0.0" | 1617 | xdg-basedir "^3.0.0" |
1761 | 1618 | ||
1762 | console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: | 1619 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: |
1763 | version "1.1.0" | 1620 | version "1.1.0" |
1764 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" | 1621 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" |
1765 | integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= | 1622 | integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= |
@@ -1769,10 +1626,12 @@ content-disposition@0.5.1: | |||
1769 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" | 1626 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.1.tgz#87476c6a67c8daa87e32e87616df883ba7fb071b" |
1770 | integrity sha1-h0dsamfI2qh+Muh2Ft+IO6f7Bxs= | 1627 | integrity sha1-h0dsamfI2qh+Muh2Ft+IO6f7Bxs= |
1771 | 1628 | ||
1772 | content-disposition@0.5.2: | 1629 | content-disposition@0.5.3: |
1773 | version "0.5.2" | 1630 | version "0.5.3" |
1774 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" | 1631 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" |
1775 | integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= | 1632 | integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== |
1633 | dependencies: | ||
1634 | safe-buffer "5.1.2" | ||
1776 | 1635 | ||
1777 | content-security-policy-builder@2.0.0: | 1636 | content-security-policy-builder@2.0.0: |
1778 | version "2.0.0" | 1637 | version "2.0.0" |
@@ -1807,32 +1666,25 @@ cookie@0.3.1: | |||
1807 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" | 1666 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" |
1808 | integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= | 1667 | integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= |
1809 | 1668 | ||
1669 | cookie@0.4.0: | ||
1670 | version "0.4.0" | ||
1671 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" | ||
1672 | integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== | ||
1673 | |||
1810 | cookiejar@^2.1.0: | 1674 | cookiejar@^2.1.0: |
1811 | version "2.1.2" | 1675 | version "2.1.2" |
1812 | resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" | 1676 | resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" |
1813 | integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== | 1677 | integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== |
1814 | 1678 | ||
1815 | copy-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 | |||
1827 | copy-descriptor@^0.1.0: | 1679 | copy-descriptor@^0.1.0: |
1828 | version "0.1.1" | 1680 | version "0.1.1" |
1829 | resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" | 1681 | resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" |
1830 | integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= | 1682 | integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= |
1831 | 1683 | ||
1832 | core-js@^2.5.7: | 1684 | core-js@^2.5.7: |
1833 | version "2.6.5" | 1685 | version "2.6.9" |
1834 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" | 1686 | 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== | 1687 | integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== |
1836 | 1688 | ||
1837 | core-util-is@1.0.2, core-util-is@~1.0.0: | 1689 | core-util-is@1.0.2, core-util-is@~1.0.0: |
1838 | version "1.0.2" | 1690 | version "1.0.2" |
@@ -1847,14 +1699,14 @@ cors@^2.8.1: | |||
1847 | object-assign "^4" | 1699 | object-assign "^4" |
1848 | vary "^1" | 1700 | vary "^1" |
1849 | 1701 | ||
1850 | cosmiconfig@^5.0.2, cosmiconfig@^5.0.7: | 1702 | cosmiconfig@^5.2.0: |
1851 | version "5.2.0" | 1703 | version "5.2.1" |
1852 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.0.tgz#45038e4d28a7fe787203aede9c25bca4a08b12c8" | 1704 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" |
1853 | integrity sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g== | 1705 | integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== |
1854 | dependencies: | 1706 | dependencies: |
1855 | import-fresh "^2.0.0" | 1707 | import-fresh "^2.0.0" |
1856 | is-directory "^0.3.1" | 1708 | is-directory "^0.3.1" |
1857 | js-yaml "^3.13.0" | 1709 | js-yaml "^3.13.1" |
1858 | parse-json "^4.0.0" | 1710 | parse-json "^4.0.0" |
1859 | 1711 | ||
1860 | create-error-class@^3.0.0: | 1712 | create-error-class@^3.0.0: |
@@ -1884,9 +1736,9 @@ create-torrent@^3.24.5, create-torrent@^3.33.0: | |||
1884 | simple-sha1 "^2.0.0" | 1736 | simple-sha1 "^2.0.0" |
1885 | 1737 | ||
1886 | cron-parser@^2.7.3: | 1738 | cron-parser@^2.7.3: |
1887 | version "2.10.0" | 1739 | version "2.11.0" |
1888 | resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.10.0.tgz#d6bed39cfa6163930f89b1ade82df7b46f52b82b" | 1740 | resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.11.0.tgz#c3bf477e01de6a56938d6625b92efd6cec30a8a5" |
1889 | integrity sha512-E181Gbg+wYT0hSikwBOokL7VHgJDYUlFsRFHIlnTP8GGefhcIyf8PSc2IXztmghj5mhAZupU0n3jKfEpZVEmVg== | 1741 | integrity sha512-L5LAGlvq2xmCLErhjQRX8IL5v72y8jhGOaxrarYOhse0kJjJGb/vY/0sV/c7F/SylJGkUIY2iZPPJXZD3glZqA== |
1890 | dependencies: | 1742 | dependencies: |
1891 | is-nan "^1.2.1" | 1743 | is-nan "^1.2.1" |
1892 | moment-timezone "^0.5.23" | 1744 | moment-timezone "^0.5.23" |
@@ -1926,11 +1778,6 @@ cycle@1.0.x: | |||
1926 | resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" | 1778 | resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" |
1927 | integrity sha1-IegLK+hYD5i0aPN5QwZisEbDStI= | 1779 | integrity sha1-IegLK+hYD5i0aPN5QwZisEbDStI= |
1928 | 1780 | ||
1929 | cyclist@~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 | |||
1934 | d@1: | 1781 | d@1: |
1935 | version "1.0.0" | 1782 | version "1.0.0" |
1936 | resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" | 1783 | resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" |
@@ -1955,14 +1802,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" | 1802 | resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" |
1956 | integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== | 1803 | integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== |
1957 | 1804 | ||
1958 | deasync@^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 | |||
1966 | debug@2.2.0, debug@~2.2.0: | 1805 | debug@2.2.0, debug@~2.2.0: |
1967 | version "2.2.0" | 1806 | version "2.2.0" |
1968 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" | 1807 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" |
@@ -1977,21 +1816,14 @@ debug@2.3.3: | |||
1977 | dependencies: | 1816 | dependencies: |
1978 | ms "0.7.2" | 1817 | ms "0.7.2" |
1979 | 1818 | ||
1980 | debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: | 1819 | debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.3.3: |
1981 | version "2.6.9" | 1820 | version "2.6.9" |
1982 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" | 1821 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" |
1983 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== | 1822 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== |
1984 | dependencies: | 1823 | dependencies: |
1985 | ms "2.0.0" | 1824 | ms "2.0.0" |
1986 | 1825 | ||
1987 | debug@3.1.0, debug@~3.1.0: | 1826 | debug@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 | |||
1994 | debug@3.2.6, debug@^3.1.0: | ||
1995 | version "3.2.6" | 1827 | version "3.2.6" |
1996 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" | 1828 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" |
1997 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== | 1829 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== |
@@ -2005,12 +1837,19 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0: | |||
2005 | dependencies: | 1837 | dependencies: |
2006 | ms "^2.1.1" | 1838 | ms "^2.1.1" |
2007 | 1839 | ||
2008 | debuglog@^1.0.0, debuglog@^1.0.1: | 1840 | debug@~3.1.0: |
1841 | version "3.1.0" | ||
1842 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" | ||
1843 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== | ||
1844 | dependencies: | ||
1845 | ms "2.0.0" | ||
1846 | |||
1847 | debuglog@^1.0.0: | ||
2009 | version "1.0.1" | 1848 | version "1.0.1" |
2010 | resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" | 1849 | resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" |
2011 | integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= | 1850 | integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= |
2012 | 1851 | ||
2013 | decamelize@^1.1.1, decamelize@^1.2.0: | 1852 | decamelize@^1.2.0: |
2014 | version "1.2.0" | 1853 | version "1.2.0" |
2015 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" | 1854 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" |
2016 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= | 1855 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= |
@@ -2066,13 +1905,6 @@ deep-object-diff@^1.1.0: | |||
2066 | resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a" | 1905 | resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a" |
2067 | integrity sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw== | 1906 | integrity sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw== |
2068 | 1907 | ||
2069 | defaults@^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 | |||
2076 | define-properties@^1.1.1, define-properties@^1.1.2: | 1908 | define-properties@^1.1.1, define-properties@^1.1.2: |
2077 | version "1.1.3" | 1909 | version "1.1.3" |
2078 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" | 1910 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" |
@@ -2130,9 +1962,9 @@ delegates@^1.0.0: | |||
2130 | integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= | 1962 | integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= |
2131 | 1963 | ||
2132 | denque@^1.1.0: | 1964 | denque@^1.1.0: |
2133 | version "1.4.0" | 1965 | version "1.4.1" |
2134 | resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.0.tgz#79e2f0490195502107f24d9553f374837dabc916" | 1966 | resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf" |
2135 | integrity sha512-gh513ac7aiKrAgjiIBWZG0EASyDF9p4JMWwKA8YU5s9figrL5SRNEMT6FDynsegakuhWd1wVqTvqvqAoDxw7wQ== | 1967 | integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ== |
2136 | 1968 | ||
2137 | depd@2.0.0: | 1969 | depd@2.0.0: |
2138 | version "2.0.0" | 1970 | version "2.0.0" |
@@ -2144,46 +1976,16 @@ depd@~1.1.0, depd@~1.1.2: | |||
2144 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" | 1976 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" |
2145 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= | 1977 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= |
2146 | 1978 | ||
2147 | descrevit@^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 | |||
2154 | destroy@~1.0.4: | 1979 | destroy@~1.0.4: |
2155 | version "1.0.4" | 1980 | version "1.0.4" |
2156 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" | 1981 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" |
2157 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= | 1982 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= |
2158 | 1983 | ||
2159 | detect-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 | |||
2164 | detect-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 | |||
2169 | detect-libc@^1.0.2, detect-libc@^1.0.3: | 1984 | detect-libc@^1.0.2, detect-libc@^1.0.3: |
2170 | version "1.0.3" | 1985 | version "1.0.3" |
2171 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" | 1986 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" |
2172 | integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= | 1987 | integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= |
2173 | 1988 | ||
2174 | detect-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 | |||
2179 | dezalgo@^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 | |||
2187 | diagnostics@^1.1.1: | 1989 | diagnostics@^1.1.1: |
2188 | version "1.1.1" | 1990 | version "1.1.1" |
2189 | resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a" | 1991 | resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a" |
@@ -2201,21 +2003,21 @@ dicer@0.2.5: | |||
2201 | readable-stream "1.1.x" | 2003 | readable-stream "1.1.x" |
2202 | streamsearch "0.1.2" | 2004 | streamsearch "0.1.2" |
2203 | 2005 | ||
2204 | diff@3.5.0, diff@^3.1.0, diff@^3.2.0: | 2006 | diff@3.5.0, diff@^3.2.0: |
2205 | version "3.5.0" | 2007 | version "3.5.0" |
2206 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" | 2008 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" |
2207 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== | 2009 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== |
2208 | 2010 | ||
2011 | diff@^4.0.1: | ||
2012 | version "4.0.1" | ||
2013 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff" | ||
2014 | integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q== | ||
2015 | |||
2209 | dns-prefetch-control@0.1.0: | 2016 | dns-prefetch-control@0.1.0: |
2210 | version "0.1.0" | 2017 | version "0.1.0" |
2211 | resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz#60ddb457774e178f1f9415f0cabb0e85b0b300b2" | 2018 | resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.1.0.tgz#60ddb457774e178f1f9415f0cabb0e85b0b300b2" |
2212 | integrity sha1-YN20V3dOF48flBXwyrsOhbCzALI= | 2019 | integrity sha1-YN20V3dOF48flBXwyrsOhbCzALI= |
2213 | 2020 | ||
2214 | docopt@~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 | |||
2219 | doctrine@0.7.2: | 2021 | doctrine@0.7.2: |
2220 | version "0.7.2" | 2022 | version "0.7.2" |
2221 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523" | 2023 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523" |
@@ -2237,14 +2039,6 @@ dont-sniff-mimetype@1.0.0: | |||
2237 | resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58" | 2039 | resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.0.0.tgz#5932890dc9f4e2f19e5eb02a20026e5e5efc8f58" |
2238 | integrity sha1-WTKJDcn04vGeXrAqIAJuXl78j1g= | 2040 | integrity sha1-WTKJDcn04vGeXrAqIAJuXl78j1g= |
2239 | 2041 | ||
2240 | dot-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 | |||
2248 | dot-prop@^4.1.0: | 2042 | dot-prop@^4.1.0: |
2249 | version "4.2.0" | 2043 | version "4.2.0" |
2250 | resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" | 2044 | resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" |
@@ -2252,11 +2046,6 @@ dot-prop@^4.1.0: | |||
2252 | dependencies: | 2046 | dependencies: |
2253 | is-obj "^1.0.0" | 2047 | is-obj "^1.0.0" |
2254 | 2048 | ||
2255 | dotenv@^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 | |||
2260 | dottie@^2.0.0: | 2049 | dottie@^2.0.0: |
2261 | version "2.0.1" | 2050 | version "2.0.1" |
2262 | resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.1.tgz#697ad9d72004db7574d21f892466a3c285893659" | 2051 | resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.1.tgz#697ad9d72004db7574d21f892466a3c285893659" |
@@ -2272,7 +2061,7 @@ duplexer3@^0.1.4: | |||
2272 | resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" | 2061 | resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" |
2273 | integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= | 2062 | integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= |
2274 | 2063 | ||
2275 | duplexify@^3.2.0, duplexify@^3.4.2, duplexify@^3.5.0, duplexify@^3.6.0: | 2064 | duplexify@^3.2.0, duplexify@^3.5.0, duplexify@^3.6.0: |
2276 | version "3.7.1" | 2065 | version "3.7.1" |
2277 | resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" | 2066 | resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" |
2278 | integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== | 2067 | integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== |
@@ -2297,11 +2086,6 @@ ecdsa-sig-formatter@1.0.11: | |||
2297 | dependencies: | 2086 | dependencies: |
2298 | safe-buffer "^5.0.1" | 2087 | safe-buffer "^5.0.1" |
2299 | 2088 | ||
2300 | editor@~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 | |||
2305 | ee-first@1.1.1: | 2089 | ee-first@1.1.1: |
2306 | version "1.1.1" | 2090 | version "1.1.1" |
2307 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" | 2091 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" |
@@ -2322,6 +2106,11 @@ elliptic@=3.0.3: | |||
2322 | hash.js "^1.0.0" | 2106 | hash.js "^1.0.0" |
2323 | inherits "^2.0.1" | 2107 | inherits "^2.0.1" |
2324 | 2108 | ||
2109 | emoji-regex@^7.0.1: | ||
2110 | version "7.0.3" | ||
2111 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" | ||
2112 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== | ||
2113 | |||
2325 | enabled@1.0.x: | 2114 | enabled@1.0.x: |
2326 | version "1.0.2" | 2115 | version "1.0.2" |
2327 | resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93" | 2116 | resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93" |
@@ -2334,7 +2123,7 @@ encodeurl@~1.0.2: | |||
2334 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" | 2123 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" |
2335 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= | 2124 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= |
2336 | 2125 | ||
2337 | encoding@^0.1.11, encoding@^0.1.12, encoding@~0.1.12: | 2126 | encoding@^0.1.12, encoding@~0.1.12: |
2338 | version "0.1.12" | 2127 | version "0.1.12" |
2339 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" | 2128 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" |
2340 | integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= | 2129 | integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s= |
@@ -2435,18 +2224,6 @@ env-variable@0.0.x: | |||
2435 | resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88" | 2224 | resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88" |
2436 | integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA== | 2225 | integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA== |
2437 | 2226 | ||
2438 | err-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 | |||
2443 | errno@~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 | |||
2450 | error-ex@^1.3.1: | 2227 | error-ex@^1.3.1: |
2451 | version "1.3.2" | 2228 | version "1.3.2" |
2452 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" | 2229 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" |
@@ -2476,9 +2253,9 @@ es-to-primitive@^1.2.0: | |||
2476 | is-symbol "^1.0.2" | 2253 | is-symbol "^1.0.2" |
2477 | 2254 | ||
2478 | es5-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: | 2255 | es5-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" | 2256 | version "0.10.50" |
2480 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.49.tgz#059a239de862c94494fec28f8150c977028c6c5e" | 2257 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.50.tgz#6d0e23a0abdb27018e5ac4fd09b412bc5517a778" |
2481 | integrity sha512-3NMEhi57E31qdzmYp2jwRArIUsj1HI/RxbQ4bgnSB+AIKIxsAmTiK83bYMifIcpWvEc3P1X30DhUKOqEtF/kvg== | 2258 | integrity sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw== |
2482 | dependencies: | 2259 | dependencies: |
2483 | es6-iterator "~2.0.3" | 2260 | es6-iterator "~2.0.3" |
2484 | es6-symbol "~3.1.1" | 2261 | es6-symbol "~3.1.1" |
@@ -2505,18 +2282,6 @@ es6-map@^0.1.3: | |||
2505 | es6-symbol "~3.1.1" | 2282 | es6-symbol "~3.1.1" |
2506 | event-emitter "~0.3.5" | 2283 | event-emitter "~0.3.5" |
2507 | 2284 | ||
2508 | es6-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 | |||
2513 | es6-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 | |||
2520 | es6-promisify@^6.0.0: | 2285 | es6-promisify@^6.0.0: |
2521 | version "6.0.1" | 2286 | version "6.0.1" |
2522 | resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.1.tgz#6edaa45f3bd570ffe08febce66f7116be4b1cdb6" | 2287 | resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.1.tgz#6edaa45f3bd570ffe08febce66f7116be4b1cdb6" |
@@ -2663,19 +2428,6 @@ event-emitter@^0.3.5, event-emitter@~0.3.5: | |||
2663 | d "1" | 2428 | d "1" |
2664 | es5-ext "~0.10.14" | 2429 | es5-ext "~0.10.14" |
2665 | 2430 | ||
2666 | execa@^0.10.0: | ||
2667 | version "0.10.0" | ||
2668 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" | ||
2669 | integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== | ||
2670 | dependencies: | ||
2671 | cross-spawn "^6.0.0" | ||
2672 | get-stream "^3.0.0" | ||
2673 | is-stream "^1.1.0" | ||
2674 | npm-run-path "^2.0.0" | ||
2675 | p-finally "^1.0.0" | ||
2676 | signal-exit "^3.0.0" | ||
2677 | strip-eof "^1.0.0" | ||
2678 | |||
2679 | execa@^0.7.0: | 2431 | execa@^0.7.0: |
2680 | version "0.7.0" | 2432 | version "0.7.0" |
2681 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" | 2433 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" |
@@ -2725,17 +2477,10 @@ expand-template@^2.0.3: | |||
2725 | resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" | 2477 | resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" |
2726 | integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== | 2478 | integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== |
2727 | 2479 | ||
2728 | expand-tilde@^2.0.0, expand-tilde@^2.0.2: | 2480 | expect-ct@0.2.0: |
2729 | version "2.0.2" | 2481 | version "0.2.0" |
2730 | resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" | 2482 | resolved "https://registry.yarnpkg.com/expect-ct/-/expect-ct-0.2.0.tgz#3a54741b6ed34cc7a93305c605f63cd268a54a62" |
2731 | integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= | 2483 | integrity sha512-6SK3MG/Bbhm8MsgyJAylg+ucIOU71/FzyFalcfu5nY19dH8y/z0tBJU0wrNBXD4B27EoQtqPF/9wqH0iYAd04g== |
2732 | dependencies: | ||
2733 | homedir-polyfill "^1.0.1" | ||
2734 | |||
2735 | expect-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 | 2484 | ||
2740 | express-oauth-server@^2.0.0: | 2485 | express-oauth-server@^2.0.0: |
2741 | version "2.0.0" | 2486 | version "2.0.0" |
@@ -2746,12 +2491,10 @@ express-oauth-server@^2.0.0: | |||
2746 | express "^4.13.3" | 2491 | express "^4.13.3" |
2747 | oauth2-server "3.0.0" | 2492 | oauth2-server "3.0.0" |
2748 | 2493 | ||
2749 | express-rate-limit@^3.1.0: | 2494 | express-rate-limit@^4.0.4: |
2750 | version "3.4.0" | 2495 | version "4.0.4" |
2751 | resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-3.4.0.tgz#c053ee294feac6d3529863de549438749fd83ef1" | 2496 | 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== | 2497 | integrity sha512-DLRj2vMO7Xgai8qWKU9O6ZztF2bdDmfFNFi9k3G9BPzJ+7MG7eWaaBikbe0eBpNGSxU8JziwW0PQKG78aNWa6g== |
2753 | dependencies: | ||
2754 | defaults "^1.0.3" | ||
2755 | 2498 | ||
2756 | express-validator@^5.0.0: | 2499 | express-validator@^5.0.0: |
2757 | version "5.3.1" | 2500 | version "5.3.1" |
@@ -2793,38 +2536,38 @@ express@4.13.4: | |||
2793 | vary "~1.0.1" | 2536 | vary "~1.0.1" |
2794 | 2537 | ||
2795 | express@^4.12.4, express@^4.13.3: | 2538 | express@^4.12.4, express@^4.13.3: |
2796 | version "4.16.4" | 2539 | version "4.17.1" |
2797 | resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" | 2540 | resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" |
2798 | integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== | 2541 | integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== |
2799 | dependencies: | 2542 | dependencies: |
2800 | accepts "~1.3.5" | 2543 | accepts "~1.3.7" |
2801 | array-flatten "1.1.1" | 2544 | array-flatten "1.1.1" |
2802 | body-parser "1.18.3" | 2545 | body-parser "1.19.0" |
2803 | content-disposition "0.5.2" | 2546 | content-disposition "0.5.3" |
2804 | content-type "~1.0.4" | 2547 | content-type "~1.0.4" |
2805 | cookie "0.3.1" | 2548 | cookie "0.4.0" |
2806 | cookie-signature "1.0.6" | 2549 | cookie-signature "1.0.6" |
2807 | debug "2.6.9" | 2550 | debug "2.6.9" |
2808 | depd "~1.1.2" | 2551 | depd "~1.1.2" |
2809 | encodeurl "~1.0.2" | 2552 | encodeurl "~1.0.2" |
2810 | escape-html "~1.0.3" | 2553 | escape-html "~1.0.3" |
2811 | etag "~1.8.1" | 2554 | etag "~1.8.1" |
2812 | finalhandler "1.1.1" | 2555 | finalhandler "~1.1.2" |
2813 | fresh "0.5.2" | 2556 | fresh "0.5.2" |
2814 | merge-descriptors "1.0.1" | 2557 | merge-descriptors "1.0.1" |
2815 | methods "~1.1.2" | 2558 | methods "~1.1.2" |
2816 | on-finished "~2.3.0" | 2559 | on-finished "~2.3.0" |
2817 | parseurl "~1.3.2" | 2560 | parseurl "~1.3.3" |
2818 | path-to-regexp "0.1.7" | 2561 | path-to-regexp "0.1.7" |
2819 | proxy-addr "~2.0.4" | 2562 | proxy-addr "~2.0.5" |
2820 | qs "6.5.2" | 2563 | qs "6.7.0" |
2821 | range-parser "~1.2.0" | 2564 | range-parser "~1.2.1" |
2822 | safe-buffer "5.1.2" | 2565 | safe-buffer "5.1.2" |
2823 | send "0.16.2" | 2566 | send "0.17.1" |
2824 | serve-static "1.13.2" | 2567 | serve-static "1.14.1" |
2825 | setprototypeof "1.1.0" | 2568 | setprototypeof "1.1.1" |
2826 | statuses "~1.4.0" | 2569 | statuses "~1.5.0" |
2827 | type-is "~1.6.16" | 2570 | type-is "~1.6.18" |
2828 | utils-merge "1.0.1" | 2571 | utils-merge "1.0.1" |
2829 | vary "~1.1.2" | 2572 | vary "~1.1.2" |
2830 | 2573 | ||
@@ -2897,21 +2640,16 @@ fast-safe-stringify@^2.0.4: | |||
2897 | resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz#04b26106cc56681f51a044cfc0d76cf0008ac2c2" | 2640 | resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz#04b26106cc56681f51a044cfc0d76cf0008ac2c2" |
2898 | integrity sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg== | 2641 | integrity sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg== |
2899 | 2642 | ||
2900 | feature-policy@0.2.0: | 2643 | feature-policy@0.3.0: |
2901 | version "0.2.0" | 2644 | version "0.3.0" |
2902 | resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.2.0.tgz#22096de49ab240176878ffe2bde2f6ff04d48c43" | 2645 | resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.3.0.tgz#7430e8e54a40da01156ca30aaec1a381ce536069" |
2903 | integrity sha512-2hGrlv6efG4hscYVZeaYjpzpT6I2OZgYqE2yDUzeAcKj2D1SH0AsEzqJNXzdoglEddcIXQQYop3lD97XpG75Jw== | 2646 | integrity sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ== |
2904 | 2647 | ||
2905 | fecha@^2.3.3: | 2648 | fecha@^2.3.3: |
2906 | version "2.3.3" | 2649 | version "2.3.3" |
2907 | resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd" | 2650 | resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd" |
2908 | integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg== | 2651 | integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg== |
2909 | 2652 | ||
2910 | figgy-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 | |||
2915 | figures@^1.3.5, figures@^1.7.0: | 2653 | figures@^1.3.5, figures@^1.7.0: |
2916 | version "1.7.0" | 2654 | version "1.7.0" |
2917 | resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" | 2655 | resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" |
@@ -2970,52 +2708,32 @@ finalhandler@0.4.1: | |||
2970 | on-finished "~2.3.0" | 2708 | on-finished "~2.3.0" |
2971 | unpipe "~1.0.0" | 2709 | unpipe "~1.0.0" |
2972 | 2710 | ||
2973 | finalhandler@1.1.1: | 2711 | finalhandler@~1.1.2: |
2974 | version "1.1.1" | 2712 | version "1.1.2" |
2975 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" | 2713 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" |
2976 | integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== | 2714 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== |
2977 | dependencies: | 2715 | dependencies: |
2978 | debug "2.6.9" | 2716 | debug "2.6.9" |
2979 | encodeurl "~1.0.2" | 2717 | encodeurl "~1.0.2" |
2980 | escape-html "~1.0.3" | 2718 | escape-html "~1.0.3" |
2981 | on-finished "~2.3.0" | 2719 | on-finished "~2.3.0" |
2982 | parseurl "~1.3.2" | 2720 | parseurl "~1.3.3" |
2983 | statuses "~1.4.0" | 2721 | statuses "~1.5.0" |
2984 | unpipe "~1.0.0" | 2722 | unpipe "~1.0.0" |
2985 | 2723 | ||
2986 | find-npm-prefix@^1.0.2: | 2724 | find-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 | |||
2991 | find-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 | |||
2996 | find-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 | |||
3003 | find-up@^3.0.0: | ||
3004 | version "3.0.0" | 2725 | version "3.0.0" |
3005 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" | 2726 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" |
3006 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== | 2727 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== |
3007 | dependencies: | 2728 | dependencies: |
3008 | locate-path "^3.0.0" | 2729 | locate-path "^3.0.0" |
3009 | 2730 | ||
3010 | findup-sync@2.0.0: | 2731 | find-up@^4.0.0: |
3011 | version "2.0.0" | 2732 | version "4.0.0" |
3012 | resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" | 2733 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.0.0.tgz#c367f8024de92efb75f2d4906536d24682065c3a" |
3013 | integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw= | 2734 | integrity sha512-zoH7ZWPkRdgwYCDVoQTzqjG8JSPANhtvLhh4KVUHyKnaUJJrNeFmWIkTcNuJmR3GLMEmGYEf2S2bjgx26JTF+Q== |
3014 | dependencies: | 2735 | dependencies: |
3015 | detect-file "^1.0.0" | 2736 | locate-path "^5.0.0" |
3016 | is-glob "^3.1.0" | ||
3017 | micromatch "^3.0.4" | ||
3018 | resolve-dir "^1.0.1" | ||
3019 | 2737 | ||
3020 | flat-cache@^1.2.1: | 2738 | flat-cache@^1.2.1: |
3021 | version "1.3.4" | 2739 | version "1.3.4" |
@@ -3039,11 +2757,6 @@ flatten@^1.0.2: | |||
3039 | resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" | 2757 | resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" |
3040 | integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I= | 2758 | integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I= |
3041 | 2759 | ||
3042 | flexbuffer@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 | |||
3047 | fluent-ffmpeg@^2.1.0: | 2760 | fluent-ffmpeg@^2.1.0: |
3048 | version "2.1.2" | 2761 | version "2.1.2" |
3049 | resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74" | 2762 | resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74" |
@@ -3052,14 +2765,6 @@ fluent-ffmpeg@^2.1.0: | |||
3052 | async ">=0.2.9" | 2765 | async ">=0.2.9" |
3053 | which "^1.1.1" | 2766 | which "^1.1.1" |
3054 | 2767 | ||
3055 | flush-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 | |||
3063 | fn-name@~2.0.1: | 2768 | fn-name@~2.0.1: |
3064 | version "2.0.1" | 2769 | version "2.0.1" |
3065 | resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7" | 2770 | resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7" |
@@ -3106,10 +2811,10 @@ fragment-cache@^0.2.1: | |||
3106 | dependencies: | 2811 | dependencies: |
3107 | map-cache "^0.2.2" | 2812 | map-cache "^0.2.2" |
3108 | 2813 | ||
3109 | frameguard@3.0.0: | 2814 | frameguard@3.1.0: |
3110 | version "3.0.0" | 2815 | version "3.1.0" |
3111 | resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.0.0.tgz#7bcad469ee7b96e91d12ceb3959c78235a9272e9" | 2816 | resolved "https://registry.yarnpkg.com/frameguard/-/frameguard-3.1.0.tgz#bd1442cca1d67dc346a6751559b6d04502103a22" |
3112 | integrity sha1-e8rUae57lukdEs6zlZx4I1qScuk= | 2817 | integrity sha512-TxgSKM+7LTA6sidjOiSZK9wxY0ffMPY3Wta//MqwmX0nZuEHc8QrkV8Fh3ZhMJeiH+Uyh/tcaarImRy8u77O7g== |
3113 | 2818 | ||
3114 | fresh@0.3.0: | 2819 | fresh@0.3.0: |
3115 | version "0.3.0" | 2820 | version "0.3.0" |
@@ -3121,22 +2826,6 @@ fresh@0.5.2: | |||
3121 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" | 2826 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" |
3122 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= | 2827 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= |
3123 | 2828 | ||
3124 | from2@^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 | |||
3132 | from2@^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 | |||
3140 | front-matter@2.1.2: | 2829 | front-matter@2.1.2: |
3141 | version "2.1.2" | 2830 | version "2.1.2" |
3142 | resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-2.1.2.tgz#f75983b9f2f413be658c93dfd7bd8ce4078f5cdb" | 2831 | resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-2.1.2.tgz#f75983b9f2f413be658c93dfd7bd8ce4078f5cdb" |
@@ -3175,63 +2864,34 @@ fs-extra@^3.0.1: | |||
3175 | jsonfile "^3.0.0" | 2864 | jsonfile "^3.0.0" |
3176 | universalify "^0.1.0" | 2865 | universalify "^0.1.0" |
3177 | 2866 | ||
3178 | fs-extra@^7.0.0: | 2867 | fs-extra@^8.0.1: |
3179 | version "7.0.1" | 2868 | version "8.0.1" |
3180 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" | 2869 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.0.1.tgz#90294081f978b1f182f347a440a209154344285b" |
3181 | integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== | 2870 | integrity sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A== |
3182 | dependencies: | 2871 | dependencies: |
3183 | graceful-fs "^4.1.2" | 2872 | graceful-fs "^4.1.2" |
3184 | jsonfile "^4.0.0" | 2873 | jsonfile "^4.0.0" |
3185 | universalify "^0.1.0" | 2874 | universalify "^0.1.0" |
3186 | 2875 | ||
3187 | fs-minipass@^1.2.5: | 2876 | fs-minipass@^1.2.5: |
3188 | version "1.2.5" | 2877 | version "1.2.6" |
3189 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" | 2878 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" |
3190 | integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== | 2879 | integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== |
3191 | dependencies: | 2880 | dependencies: |
3192 | minipass "^2.2.1" | 2881 | minipass "^2.2.1" |
3193 | 2882 | ||
3194 | fs-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 | |||
3203 | fs-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 | |||
3213 | fs.realpath@^1.0.0: | 2883 | fs.realpath@^1.0.0: |
3214 | version "1.0.0" | 2884 | version "1.0.0" |
3215 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" | 2885 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" |
3216 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= | 2886 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= |
3217 | 2887 | ||
3218 | fsevents@^1.2.7: | 2888 | fsevents@^1.2.7: |
3219 | version "1.2.7" | 2889 | version "1.2.9" |
3220 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" | 2890 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" |
3221 | integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== | 2891 | integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== |
3222 | dependencies: | 2892 | dependencies: |
3223 | nan "^2.9.2" | 2893 | nan "^2.12.1" |
3224 | node-pre-gyp "^0.10.0" | 2894 | node-pre-gyp "^0.12.0" |
3225 | |||
3226 | fstream@^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: | ||
3231 | graceful-fs "^4.1.2" | ||
3232 | inherits "~2.0.0" | ||
3233 | mkdirp ">=0.5 0" | ||
3234 | rimraf "2" | ||
3235 | 2895 | ||
3236 | function-bind@^1.1.1: | 2896 | function-bind@^1.1.1: |
3237 | version "1.1.1" | 2897 | version "1.1.1" |
@@ -3275,25 +2935,6 @@ generate-object-property@^1.1.0: | |||
3275 | dependencies: | 2935 | dependencies: |
3276 | is-property "^1.0.0" | 2936 | is-property "^1.0.0" |
3277 | 2937 | ||
3278 | genfun@^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 | |||
3283 | gentle-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 | |||
3297 | get-browser-rtc@^1.0.0: | 2938 | get-browser-rtc@^1.0.0: |
3298 | version "1.0.2" | 2939 | version "1.0.2" |
3299 | resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz#bbcd40c8451a7ed4ef5c373b8169a409dd1d11d9" | 2940 | resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.0.2.tgz#bbcd40c8451a7ed4ef5c373b8169a409dd1d11d9" |
@@ -3304,6 +2945,11 @@ get-caller-file@^1.0.1: | |||
3304 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" | 2945 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" |
3305 | integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== | 2946 | integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== |
3306 | 2947 | ||
2948 | get-caller-file@^2.0.1: | ||
2949 | version "2.0.5" | ||
2950 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" | ||
2951 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== | ||
2952 | |||
3307 | get-func-name@^2.0.0: | 2953 | get-func-name@^2.0.0: |
3308 | version "2.0.0" | 2954 | version "2.0.0" |
3309 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" | 2955 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" |
@@ -3314,22 +2960,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" | 2960 | 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== | 2961 | integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg== |
3316 | 2962 | ||
3317 | get-port@latest: | 2963 | get-port@^5.0.0: |
3318 | version "4.2.0" | 2964 | version "5.0.0" |
3319 | resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" | 2965 | resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.0.0.tgz#aa22b6b86fd926dd7884de3e23332c9f70c031a6" |
3320 | integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw== | 2966 | integrity sha512-imzMU0FjsZqNa6BqOjbbW6w5BivHIuQKopjpPqcnx0AVHJQKCxK1O+Ab3OrVXhrekqfVMjwA9ZYu062R+KcIsQ== |
2967 | dependencies: | ||
2968 | type-fest "^0.3.0" | ||
3321 | 2969 | ||
3322 | get-stdin@^6.0.0: | 2970 | get-stdin@^6.0.0: |
3323 | version "6.0.0" | 2971 | version "6.0.0" |
3324 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" | 2972 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" |
3325 | integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== | 2973 | integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== |
3326 | 2974 | ||
2975 | get-stdin@^7.0.0: | ||
2976 | version "7.0.0" | ||
2977 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6" | ||
2978 | integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== | ||
2979 | |||
3327 | get-stream@^3.0.0: | 2980 | get-stream@^3.0.0: |
3328 | version "3.0.0" | 2981 | version "3.0.0" |
3329 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" | 2982 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" |
3330 | integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= | 2983 | integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= |
3331 | 2984 | ||
3332 | get-stream@^4.0.0, get-stream@^4.1.0: | 2985 | get-stream@^4.0.0: |
3333 | version "4.1.0" | 2986 | version "4.1.0" |
3334 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" | 2987 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" |
3335 | integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== | 2988 | integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== |
@@ -3373,7 +3026,7 @@ glob@7.1.2: | |||
3373 | once "^1.3.0" | 3026 | once "^1.3.0" |
3374 | path-is-absolute "^1.0.0" | 3027 | path-is-absolute "^1.0.0" |
3375 | 3028 | ||
3376 | glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@~7.1.1: | 3029 | glob@7.1.3: |
3377 | version "7.1.3" | 3030 | version "7.1.3" |
3378 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" | 3031 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" |
3379 | integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== | 3032 | integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== |
@@ -3385,6 +3038,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" | 3038 | once "^1.3.0" |
3386 | path-is-absolute "^1.0.0" | 3039 | path-is-absolute "^1.0.0" |
3387 | 3040 | ||
3041 | glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@~7.1.1: | ||
3042 | version "7.1.4" | ||
3043 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" | ||
3044 | integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== | ||
3045 | dependencies: | ||
3046 | fs.realpath "^1.0.0" | ||
3047 | inflight "^1.0.4" | ||
3048 | inherits "2" | ||
3049 | minimatch "^3.0.4" | ||
3050 | once "^1.3.0" | ||
3051 | path-is-absolute "^1.0.0" | ||
3052 | |||
3388 | global-dirs@^0.1.0: | 3053 | global-dirs@^0.1.0: |
3389 | version "0.1.1" | 3054 | version "0.1.1" |
3390 | resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" | 3055 | resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" |
@@ -3392,26 +3057,6 @@ global-dirs@^0.1.0: | |||
3392 | dependencies: | 3057 | dependencies: |
3393 | ini "^1.3.4" | 3058 | ini "^1.3.4" |
3394 | 3059 | ||
3395 | global-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 | |||
3404 | global-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 | |||
3415 | globals@^9.2.0: | 3060 | globals@^9.2.0: |
3416 | version "9.18.0" | 3061 | version "9.18.0" |
3417 | resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" | 3062 | resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" |
@@ -3461,7 +3106,7 @@ got@^6.7.1: | |||
3461 | unzip-response "^2.0.1" | 3106 | unzip-response "^2.0.1" |
3462 | url-parse-lax "^1.0.0" | 3107 | url-parse-lax "^1.0.0" |
3463 | 3108 | ||
3464 | graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: | 3109 | graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: |
3465 | version "4.1.15" | 3110 | version "4.1.15" |
3466 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" | 3111 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" |
3467 | integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== | 3112 | integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== |
@@ -3530,7 +3175,7 @@ has-symbols@^1.0.0: | |||
3530 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" | 3175 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" |
3531 | integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= | 3176 | integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= |
3532 | 3177 | ||
3533 | has-unicode@^2.0.0, has-unicode@~2.0.1: | 3178 | has-unicode@^2.0.0: |
3534 | version "2.0.1" | 3179 | version "2.0.1" |
3535 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" | 3180 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" |
3536 | integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= | 3181 | integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= |
@@ -3609,24 +3254,24 @@ helmet-csp@2.7.1: | |||
3609 | platform "1.3.5" | 3254 | platform "1.3.5" |
3610 | 3255 | ||
3611 | helmet@^3.12.1: | 3256 | helmet@^3.12.1: |
3612 | version "3.16.0" | 3257 | version "3.18.0" |
3613 | resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.16.0.tgz#7df41a4bfe4c83d90147c1e30d70893f92a9d97c" | 3258 | resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.18.0.tgz#37666f7c861bd1ff3015e0cdb903a43501e3da3e" |
3614 | integrity sha512-rsTKRogc5OYGlvSHuq5QsmOsOzF6uDoMqpfh+Np8r23+QxDq+SUx90Rf8HyIKQVl7H6NswZEwfcykinbAeZ6UQ== | 3259 | integrity sha512-TsKlGE5UVkV0NiQ4PllV9EVfZklPjyzcMEMjWlyI/8S6epqgRT+4s4GHVgc25x0TixsKvp3L7c91HQQt5l0+QA== |
3615 | dependencies: | 3260 | dependencies: |
3616 | depd "2.0.0" | 3261 | depd "2.0.0" |
3617 | dns-prefetch-control "0.1.0" | 3262 | dns-prefetch-control "0.1.0" |
3618 | dont-sniff-mimetype "1.0.0" | 3263 | dont-sniff-mimetype "1.0.0" |
3619 | expect-ct "0.1.1" | 3264 | expect-ct "0.2.0" |
3620 | feature-policy "0.2.0" | 3265 | feature-policy "0.3.0" |
3621 | frameguard "3.0.0" | 3266 | frameguard "3.1.0" |
3622 | helmet-crossdomain "0.3.0" | 3267 | helmet-crossdomain "0.3.0" |
3623 | helmet-csp "2.7.1" | 3268 | helmet-csp "2.7.1" |
3624 | hide-powered-by "1.0.0" | 3269 | hide-powered-by "1.0.0" |
3625 | hpkp "2.0.0" | 3270 | hpkp "2.0.0" |
3626 | hsts "2.2.0" | 3271 | hsts "2.2.0" |
3627 | ienoopen "1.1.0" | 3272 | ienoopen "1.1.0" |
3628 | nocache "2.0.0" | 3273 | nocache "2.1.0" |
3629 | referrer-policy "1.1.0" | 3274 | referrer-policy "1.2.0" |
3630 | x-xss-protection "1.1.0" | 3275 | x-xss-protection "1.1.0" |
3631 | 3276 | ||
3632 | hh-mm-ss@~1.2.0: | 3277 | hh-mm-ss@~1.2.0: |
@@ -3641,14 +3286,7 @@ hide-powered-by@1.0.0: | |||
3641 | resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b" | 3286 | resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.0.0.tgz#4a85ad65881f62857fc70af7174a1184dccce32b" |
3642 | integrity sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys= | 3287 | integrity sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys= |
3643 | 3288 | ||
3644 | homedir-polyfill@^1.0.1: | 3289 | hosted-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 | |||
3651 | hosted-git-info@^2.1.4, hosted-git-info@^2.6.0, hosted-git-info@^2.7.1: | ||
3652 | version "2.7.1" | 3290 | version "2.7.1" |
3653 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" | 3291 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" |
3654 | integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== | 3292 | integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== |
@@ -3665,20 +3303,16 @@ hsts@2.2.0: | |||
3665 | dependencies: | 3303 | dependencies: |
3666 | depd "2.0.0" | 3304 | depd "2.0.0" |
3667 | 3305 | ||
3668 | http-cache-semantics@^3.8.1: | 3306 | http-errors@1.7.2, http-errors@~1.7.2: |
3669 | version "3.8.1" | 3307 | version "1.7.2" |
3670 | resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" | 3308 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" |
3671 | integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== | 3309 | integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== |
3672 | |||
3673 | http-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: | 3310 | dependencies: |
3678 | depd "~1.1.2" | 3311 | depd "~1.1.2" |
3679 | inherits "2.0.3" | 3312 | inherits "2.0.3" |
3680 | setprototypeof "1.1.0" | 3313 | setprototypeof "1.1.1" |
3681 | statuses ">= 1.4.0 < 2" | 3314 | statuses ">= 1.5.0 < 2" |
3315 | toidentifier "1.0.0" | ||
3682 | 3316 | ||
3683 | http-errors@~1.3.1: | 3317 | http-errors@~1.3.1: |
3684 | version "1.3.1" | 3318 | version "1.3.1" |
@@ -3688,14 +3322,6 @@ http-errors@~1.3.1: | |||
3688 | inherits "~2.0.1" | 3322 | inherits "~2.0.1" |
3689 | statuses "1" | 3323 | statuses "1" |
3690 | 3324 | ||
3691 | http-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 | |||
3699 | http-signature@^1.2.0, http-signature@~1.2.0: | 3325 | http-signature@^1.2.0, http-signature@~1.2.0: |
3700 | version "1.2.0" | 3326 | version "1.2.0" |
3701 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" | 3327 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" |
@@ -3705,50 +3331,28 @@ http-signature@^1.2.0, http-signature@~1.2.0: | |||
3705 | jsprim "^1.2.2" | 3331 | jsprim "^1.2.2" |
3706 | sshpk "^1.7.0" | 3332 | sshpk "^1.7.0" |
3707 | 3333 | ||
3708 | https-proxy-agent@^2.2.1: | 3334 | husky@^2.4.0: |
3709 | version "2.2.1" | 3335 | version "2.4.0" |
3710 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" | 3336 | resolved "https://registry.yarnpkg.com/husky/-/husky-2.4.0.tgz#1bac7c44588f6e91f808b72efc82d24a57194f36" |
3711 | integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== | 3337 | integrity sha512-3k1wuZU20gFkphNWMjh2ISCFaqfbaLY7R9FST2Mj9HeRhUK9ydj9qQR8qfXlog3EctVGsyeilcZkIT7uBZDDVA== |
3712 | dependencies: | ||
3713 | agent-base "^4.1.0" | ||
3714 | debug "^3.1.0" | ||
3715 | |||
3716 | humanize-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 | |||
3723 | husky@^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: | 3338 | dependencies: |
3728 | cosmiconfig "^5.0.7" | 3339 | cosmiconfig "^5.2.0" |
3729 | execa "^1.0.0" | 3340 | execa "^1.0.0" |
3730 | find-up "^3.0.0" | 3341 | find-up "^3.0.0" |
3731 | get-stdin "^6.0.0" | 3342 | get-stdin "^7.0.0" |
3732 | is-ci "^2.0.0" | 3343 | is-ci "^2.0.0" |
3733 | pkg-dir "^3.0.0" | 3344 | pkg-dir "^4.1.0" |
3734 | please-upgrade-node "^3.1.1" | 3345 | please-upgrade-node "^3.1.1" |
3735 | read-pkg "^4.0.1" | 3346 | read-pkg "^5.1.1" |
3736 | run-node "^1.0.0" | 3347 | run-node "^1.0.0" |
3737 | slash "^2.0.0" | 3348 | slash "^3.0.0" |
3738 | 3349 | ||
3739 | i@0.3.x: | 3350 | i@0.3.x: |
3740 | version "0.3.6" | 3351 | version "0.3.6" |
3741 | resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" | 3352 | resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" |
3742 | integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0= | 3353 | integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0= |
3743 | 3354 | ||
3744 | iconv-lite@0.4.23: | 3355 | iconv-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 | |||
3751 | iconv-lite@^0.4.4, iconv-lite@~0.4.13: | ||
3752 | version "0.4.24" | 3356 | version "0.4.24" |
3753 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" | 3357 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" |
3754 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== | 3358 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== |
@@ -3760,16 +3364,6 @@ ienoopen@1.1.0: | |||
3760 | resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.1.0.tgz#411e5d530c982287dbdc3bb31e7a9c9e32630974" | 3364 | resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.1.0.tgz#411e5d530c982287dbdc3bb31e7a9c9e32630974" |
3761 | integrity sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ== | 3365 | integrity sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ== |
3762 | 3366 | ||
3763 | iferr@^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 | |||
3768 | iferr@^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 | |||
3773 | ignore-by-default@^1.0.1: | 3367 | ignore-by-default@^1.0.1: |
3774 | version "1.0.1" | 3368 | version "1.0.1" |
3775 | resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" | 3369 | resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" |
@@ -3825,7 +3419,7 @@ inflection@1.12.0: | |||
3825 | resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" | 3419 | resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" |
3826 | integrity sha1-ogCTVlbW9fa8TcdQLhrstwMihBY= | 3420 | integrity sha1-ogCTVlbW9fa8TcdQLhrstwMihBY= |
3827 | 3421 | ||
3828 | inflight@^1.0.4, inflight@~1.0.6: | 3422 | inflight@^1.0.4: |
3829 | version "1.0.6" | 3423 | version "1.0.6" |
3830 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" | 3424 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" |
3831 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= | 3425 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= |
@@ -3833,7 +3427,7 @@ inflight@^1.0.4, inflight@~1.0.6: | |||
3833 | once "^1.3.0" | 3427 | once "^1.3.0" |
3834 | wrappy "1" | 3428 | wrappy "1" |
3835 | 3429 | ||
3836 | inherits@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: | 3430 | inherits@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" | 3431 | version "2.0.3" |
3838 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" | 3432 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" |
3839 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= | 3433 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= |
@@ -3843,25 +3437,11 @@ inherits@=2.0.1: | |||
3843 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" | 3437 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" |
3844 | integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= | 3438 | integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= |
3845 | 3439 | ||
3846 | ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: | 3440 | ini@^1.3.4, ini@~1.3.0: |
3847 | version "1.3.5" | 3441 | version "1.3.5" |
3848 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" | 3442 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" |
3849 | integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== | 3443 | integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== |
3850 | 3444 | ||
3851 | init-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 | |||
3865 | inquirer@^0.12.0: | 3445 | inquirer@^0.12.0: |
3866 | version "0.12.0" | 3446 | version "0.12.0" |
3867 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" | 3447 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" |
@@ -3881,25 +3461,19 @@ inquirer@^0.12.0: | |||
3881 | strip-ansi "^3.0.0" | 3461 | strip-ansi "^3.0.0" |
3882 | through "^2.3.6" | 3462 | through "^2.3.6" |
3883 | 3463 | ||
3884 | invert-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 | |||
3889 | invert-kv@^2.0.0: | 3464 | invert-kv@^2.0.0: |
3890 | version "2.0.0" | 3465 | version "2.0.0" |
3891 | resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" | 3466 | resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" |
3892 | integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== | 3467 | integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== |
3893 | 3468 | ||
3894 | ioredis@^4.5.1: | 3469 | ioredis@^4.5.1: |
3895 | version "4.9.0" | 3470 | version "4.9.5" |
3896 | resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.9.0.tgz#0c52de498363309ebd48b5f6695d9d432b0f6669" | 3471 | resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.9.5.tgz#0bbba0a9faae93485d3231e1b819d2d4e23271d9" |
3897 | integrity sha512-YzfCLsN++Ct43QqGK9CWxaEK6OUvJ7rnENieAPNw3DVp/oF2uBrP2NJChbhO74Ng3LWA+i5zdIEUsZYr6dKDIQ== | 3472 | integrity sha512-L9MVfvX4F3LScTMEgriCGixzqinJsYy7Mt0NPX8RyuOTmx5JW0744pM4Ze2KVQcP3J0zvKYZ1LywAB6KIq7PYg== |
3898 | dependencies: | 3473 | dependencies: |
3899 | cluster-key-slot "^1.0.6" | 3474 | cluster-key-slot "^1.0.6" |
3900 | debug "^3.1.0" | 3475 | debug "^3.1.0" |
3901 | denque "^1.1.0" | 3476 | denque "^1.1.0" |
3902 | flexbuffer "0.0.6" | ||
3903 | lodash.defaults "^4.2.0" | 3477 | lodash.defaults "^4.2.0" |
3904 | lodash.flatten "^4.4.0" | 3478 | lodash.flatten "^4.4.0" |
3905 | redis-commands "1.4.0" | 3479 | redis-commands "1.4.0" |
@@ -3907,10 +3481,10 @@ ioredis@^4.5.1: | |||
3907 | redis-parser "^3.0.0" | 3481 | redis-parser "^3.0.0" |
3908 | standard-as-callback "^2.0.1" | 3482 | standard-as-callback "^2.0.1" |
3909 | 3483 | ||
3910 | ip-anonymize@^0.0.6: | 3484 | ip-anonymize@^0.1.0: |
3911 | version "0.0.6" | 3485 | version "0.1.0" |
3912 | resolved "https://registry.yarnpkg.com/ip-anonymize/-/ip-anonymize-0.0.6.tgz#d2c513e448e874e8cc380d03404691b94b018e68" | 3486 | resolved "https://registry.yarnpkg.com/ip-anonymize/-/ip-anonymize-0.1.0.tgz#5ead504d01871c5c28189a25382f852036b57f7e" |
3913 | integrity sha1-0sUT5EjodOjMOA0DQEaRuUsBjmg= | 3487 | integrity sha512-cZJu+N5JKKFGMK0eEQWNaQMn2EhCysciVM6eotCJwfqotj16BTfVchKsJCH6mQAT9N0GC7oWRcsZ6Lb8dDiwTA== |
3914 | 3488 | ||
3915 | ip-regex@^2.1.0: | 3489 | ip-regex@^2.1.0: |
3916 | version "2.1.0" | 3490 | version "2.1.0" |
@@ -3918,13 +3492,13 @@ ip-regex@^2.1.0: | |||
3918 | integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= | 3492 | integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= |
3919 | 3493 | ||
3920 | ip-set@^1.0.0: | 3494 | ip-set@^1.0.0: |
3921 | version "1.0.1" | 3495 | version "1.0.2" |
3922 | resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.1.tgz#633b66d0bd6c8d0de968d053263c9120d3b6727e" | 3496 | resolved "https://registry.yarnpkg.com/ip-set/-/ip-set-1.0.2.tgz#be4f119f82c124836455993dfcd554639c7007de" |
3923 | integrity sha1-Yztm0L1sjQ3paNBTJjyRINO2cn4= | 3497 | integrity sha512-Mb6kv78bTi4RNAIIWL8Bbre7hXOR2pNUi3j8FaQkLaitf/ZWxkq3/iIwXNYk2ACO3IMfdVdQrOkUtwZblO7uBA== |
3924 | dependencies: | 3498 | dependencies: |
3925 | ip "^1.1.3" | 3499 | ip "^1.1.3" |
3926 | 3500 | ||
3927 | ip@^1.0.1, ip@^1.1.3, ip@^1.1.5: | 3501 | ip@^1.0.1, ip@^1.1.3: |
3928 | version "1.1.5" | 3502 | version "1.1.5" |
3929 | resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" | 3503 | resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" |
3930 | integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= | 3504 | integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= |
@@ -3934,11 +3508,6 @@ ipaddr.js@1.0.5: | |||
3934 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.0.5.tgz#5fa78cf301b825c78abc3042d812723049ea23c7" | 3508 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.0.5.tgz#5fa78cf301b825c78abc3042d812723049ea23c7" |
3935 | integrity sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c= | 3509 | integrity sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c= |
3936 | 3510 | ||
3937 | ipaddr.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 | |||
3942 | ipaddr.js@1.9.0, "ipaddr.js@>= 0.1.5", ipaddr.js@^1.0.1: | 3511 | ipaddr.js@1.9.0, "ipaddr.js@>= 0.1.5", ipaddr.js@^1.0.1: |
3943 | version "1.9.0" | 3512 | version "1.9.0" |
3944 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" | 3513 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" |
@@ -4135,9 +3704,9 @@ is-my-ip-valid@^1.0.0: | |||
4135 | integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ== | 3704 | integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ== |
4136 | 3705 | ||
4137 | is-my-json-valid@^2.10.0: | 3706 | is-my-json-valid@^2.10.0: |
4138 | version "2.19.0" | 3707 | version "2.20.0" |
4139 | resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz#8fd6e40363cd06b963fa877d444bfb5eddc62175" | 3708 | 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== | 3709 | integrity sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA== |
4141 | dependencies: | 3710 | dependencies: |
4142 | generate-function "^2.0.0" | 3711 | generate-function "^2.0.0" |
4143 | generate-object-property "^1.1.0" | 3712 | generate-object-property "^1.1.0" |
@@ -4256,7 +3825,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" | 3825 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" |
4257 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= | 3826 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= |
4258 | 3827 | ||
4259 | is-windows@^1.0.1, is-windows@^1.0.2: | 3828 | is-windows@^1.0.2: |
4260 | version "1.0.2" | 3829 | version "1.0.2" |
4261 | resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" | 3830 | resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" |
4262 | integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== | 3831 | integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== |
@@ -4282,9 +3851,9 @@ isexe@^2.0.0: | |||
4282 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= | 3851 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= |
4283 | 3852 | ||
4284 | iso-639-3@^1.0.1: | 3853 | iso-639-3@^1.0.1: |
4285 | version "1.1.0" | 3854 | version "1.2.0" |
4286 | resolved "https://registry.yarnpkg.com/iso-639-3/-/iso-639-3-1.1.0.tgz#83722daf55490a707c318ae18a33ba3bab06c843" | 3855 | resolved "https://registry.yarnpkg.com/iso-639-3/-/iso-639-3-1.2.0.tgz#eee1f5e6ca2bbb33e3ecc910857c1c12e8b295be" |
4287 | integrity sha512-l3BAnxNpyRIZA4mEzI2md/YVrxQ3hI8hiQe7TFyQknjyOh8vCzobZuAXTFHELco0FBkYRx4FkAlIqkKrHhnzgw== | 3856 | integrity sha512-jNvD2P4JHNckQH7pc0R0SQ4oPCpyEtgs0nTtjB+DZCUDdygz0cOAxlcnq5KgNjjsqMHbR4Sbgwz2+DflzAZvlQ== |
4288 | 3857 | ||
4289 | isobject@^2.0.0: | 3858 | isobject@^2.0.0: |
4290 | version "2.1.0" | 3859 | version "2.1.0" |
@@ -4303,23 +3872,15 @@ isstream@0.1.x, isstream@~0.1.2: | |||
4303 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" | 3872 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" |
4304 | integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= | 3873 | integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= |
4305 | 3874 | ||
4306 | js-tokens@^3.0.2: | 3875 | js-tokens@^4.0.0: |
4307 | version "3.0.2" | 3876 | version "4.0.0" |
4308 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" | 3877 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" |
4309 | integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= | 3878 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== |
4310 | |||
4311 | js-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 | 3879 | ||
4319 | js-yaml@^3.12.1, js-yaml@^3.13.0, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4: | 3880 | js-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" | 3881 | version "3.13.1" |
4321 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.0.tgz#38ee7178ac0eea2c97ff6d96fff4b18c7d8cf98e" | 3882 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" |
4322 | integrity sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ== | 3883 | integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== |
4323 | dependencies: | 3884 | dependencies: |
4324 | argparse "^1.0.7" | 3885 | argparse "^1.0.7" |
4325 | esprima "^4.0.0" | 3886 | esprima "^4.0.0" |
@@ -4329,7 +3890,7 @@ jsbn@~0.1.0: | |||
4329 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" | 3890 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" |
4330 | integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= | 3891 | integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= |
4331 | 3892 | ||
4332 | json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: | 3893 | json-parse-better-errors@^1.0.1: |
4333 | version "1.0.2" | 3894 | version "1.0.2" |
4334 | resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" | 3895 | resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" |
4335 | integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== | 3896 | integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== |
@@ -4425,11 +3986,6 @@ jsonld@~1.1.0: | |||
4425 | semver "^5.5.0" | 3986 | semver "^5.5.0" |
4426 | xmldom "0.1.19" | 3987 | xmldom "0.1.19" |
4427 | 3988 | ||
4428 | jsonparse@^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 | |||
4433 | jsonpointer.js@0.4.0: | 3989 | jsonpointer.js@0.4.0: |
4434 | version "0.4.0" | 3990 | version "0.4.0" |
4435 | resolved "https://registry.yarnpkg.com/jsonpointer.js/-/jsonpointer.js-0.4.0.tgz#002cb123f767aafdeb0196132ce5c4f9941ccaba" | 3991 | resolved "https://registry.yarnpkg.com/jsonpointer.js/-/jsonpointer.js-0.4.0.tgz#002cb123f767aafdeb0196132ce5c4f9941ccaba" |
@@ -4565,18 +4121,6 @@ latest-version@^3.0.0: | |||
4565 | dependencies: | 4121 | dependencies: |
4566 | package-json "^4.0.0" | 4122 | package-json "^4.0.0" |
4567 | 4123 | ||
4568 | lazy-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 | |||
4573 | lcid@^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 | |||
4580 | lcid@^2.0.0: | 4124 | lcid@^2.0.0: |
4581 | version "2.0.0" | 4125 | version "2.0.0" |
4582 | resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" | 4126 | resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" |
@@ -4592,140 +4136,6 @@ levn@^0.3.0, levn@~0.3.0: | |||
4592 | prelude-ls "~1.1.2" | 4136 | prelude-ls "~1.1.2" |
4593 | type-check "~0.3.2" | 4137 | type-check "~0.3.2" |
4594 | 4138 | ||
4595 | libcipm@^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 | |||
4616 | libnpm@^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 | |||
4642 | libnpmaccess@^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 | |||
4652 | libnpmconfig@^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 | |||
4661 | libnpmhook@^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 | |||
4671 | libnpmorg@^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 | |||
4681 | libnpmpublish@^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 | |||
4696 | libnpmsearch@^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 | |||
4705 | libnpmteam@^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 | |||
4715 | libnpx@^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 | |||
4729 | libxmljs@0.19.5: | 4139 | libxmljs@0.19.5: |
4730 | version "0.19.5" | 4140 | version "0.19.5" |
4731 | resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.19.5.tgz#b2f34cc12fd6a3e43670c604c42a902f339ea54d" | 4141 | resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.19.5.tgz#b2f34cc12fd6a3e43670c604c42a902f339ea54d" |
@@ -4736,18 +4146,17 @@ libxmljs@0.19.5: | |||
4736 | node-pre-gyp "~0.11.0" | 4146 | node-pre-gyp "~0.11.0" |
4737 | 4147 | ||
4738 | lint-staged@^8.0.4: | 4148 | lint-staged@^8.0.4: |
4739 | version "8.1.5" | 4149 | version "8.2.0" |
4740 | resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-8.1.5.tgz#372476fe1a58b8834eb562ed4c99126bd60bdd79" | 4150 | resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-8.2.0.tgz#3d4149a229580815c955047a7acd8f09054be5a9" |
4741 | integrity sha512-e5ZavfnSLcBJE1BTzRTqw6ly8OkqVyO3GL2M6teSmTBYQ/2BuueD5GIt2RPsP31u/vjKdexUyDCxSyK75q4BDA== | 4151 | integrity sha512-DxguyxGOIfb67wZ6EOrqzjAbw6ZH9XK3YS74HO+erJf6+SAQeJJPN//GBOG5xhdt2THeuXjVPaHcCYOWGZwRbA== |
4742 | dependencies: | 4152 | dependencies: |
4743 | chalk "^2.3.1" | 4153 | chalk "^2.3.1" |
4744 | commander "^2.14.1" | 4154 | commander "^2.14.1" |
4745 | cosmiconfig "^5.0.2" | 4155 | cosmiconfig "^5.2.0" |
4746 | debug "^3.1.0" | 4156 | debug "^3.1.0" |
4747 | dedent "^0.7.0" | 4157 | dedent "^0.7.0" |
4748 | del "^3.0.0" | 4158 | del "^3.0.0" |
4749 | execa "^1.0.0" | 4159 | execa "^1.0.0" |
4750 | find-parent-dir "^0.3.0" | ||
4751 | g-status "^2.0.2" | 4160 | g-status "^2.0.2" |
4752 | is-glob "^4.0.0" | 4161 | is-glob "^4.0.0" |
4753 | is-windows "^1.0.2" | 4162 | is-windows "^1.0.2" |
@@ -4764,7 +4173,7 @@ lint-staged@^8.0.4: | |||
4764 | staged-git-files "1.1.2" | 4173 | staged-git-files "1.1.2" |
4765 | string-argv "^0.0.2" | 4174 | string-argv "^0.0.2" |
4766 | stringify-object "^3.2.2" | 4175 | stringify-object "^3.2.2" |
4767 | yup "^0.26.10" | 4176 | yup "^0.27.0" |
4768 | 4177 | ||
4769 | listr-silent-renderer@^1.1.1: | 4178 | listr-silent-renderer@^1.1.1: |
4770 | version "1.1.1" | 4179 | version "1.1.1" |
@@ -4821,14 +4230,6 @@ load-ip-set@^2.1.0: | |||
4821 | simple-get "^3.0.0" | 4230 | simple-get "^3.0.0" |
4822 | split "^1.0.0" | 4231 | split "^1.0.0" |
4823 | 4232 | ||
4824 | locate-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 | |||
4832 | locate-path@^3.0.0: | 4233 | locate-path@^3.0.0: |
4833 | version "3.0.0" | 4234 | version "3.0.0" |
4834 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" | 4235 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" |
@@ -4837,49 +4238,18 @@ locate-path@^3.0.0: | |||
4837 | p-locate "^3.0.0" | 4238 | p-locate "^3.0.0" |
4838 | path-exists "^3.0.0" | 4239 | path-exists "^3.0.0" |
4839 | 4240 | ||
4840 | lock-verify@^2.0.2, lock-verify@^2.1.0: | 4241 | locate-path@^5.0.0: |
4841 | version "2.1.0" | 4242 | version "5.0.0" |
4842 | resolved "https://registry.yarnpkg.com/lock-verify/-/lock-verify-2.1.0.tgz#fff4c918b8db9497af0c5fa7f6d71555de3ceb47" | 4243 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" |
4843 | integrity sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg== | 4244 | integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== |
4844 | dependencies: | ||
4845 | npm-package-arg "^6.1.0" | ||
4846 | semver "^5.4.1" | ||
4847 | |||
4848 | lockfile@^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 | |||
4855 | lodash._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: | 4245 | dependencies: |
4860 | lodash._createset "~4.0.0" | 4246 | p-locate "^4.1.0" |
4861 | lodash._root "~3.0.0" | ||
4862 | |||
4863 | lodash._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 | |||
4868 | lodash._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 | 4247 | ||
4873 | lodash.capitalize@^4.1.0: | 4248 | lodash.capitalize@^4.1.0: |
4874 | version "4.2.1" | 4249 | version "4.2.1" |
4875 | resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9" | 4250 | resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9" |
4876 | integrity sha1-+CbJtOKoUR2E46yinbBeGk87cqk= | 4251 | integrity sha1-+CbJtOKoUR2E46yinbBeGk87cqk= |
4877 | 4252 | ||
4878 | lodash.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 | |||
4883 | lodash.defaults@^4.2.0: | 4253 | lodash.defaults@^4.2.0: |
4884 | version "4.2.0" | 4254 | version "4.2.0" |
4885 | resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" | 4255 | resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" |
@@ -4905,21 +4275,6 @@ lodash.kebabcase@^4.0.0: | |||
4905 | resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" | 4275 | resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" |
4906 | integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= | 4276 | integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= |
4907 | 4277 | ||
4908 | lodash.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 | |||
4913 | lodash.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 | |||
4918 | lodash.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 | |||
4923 | lodash@4.17.4: | 4278 | lodash@4.17.4: |
4924 | version "4.17.4" | 4279 | version "4.17.4" |
4925 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" | 4280 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" |
@@ -4974,7 +4329,7 @@ lowercase-keys@^1.0.0: | |||
4974 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" | 4329 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" |
4975 | integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== | 4330 | integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== |
4976 | 4331 | ||
4977 | lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.1.2, lru-cache@^4.1.3, lru-cache@^4.1.5: | 4332 | lru-cache@4.1.x, lru-cache@^4.0.1: |
4978 | version "4.1.5" | 4333 | version "4.1.5" |
4979 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" | 4334 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" |
4980 | integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== | 4335 | integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== |
@@ -4982,13 +4337,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" | 4337 | pseudomap "^1.0.2" |
4983 | yallist "^2.1.2" | 4338 | yallist "^2.1.2" |
4984 | 4339 | ||
4985 | lru-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 | |||
4992 | lru-queue@0.1: | 4340 | lru-queue@0.1: |
4993 | version "0.1.0" | 4341 | version "0.1.0" |
4994 | resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" | 4342 | resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" |
@@ -5049,23 +4397,6 @@ make-error@^1.1.1: | |||
5049 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" | 4397 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" |
5050 | integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== | 4398 | integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== |
5051 | 4399 | ||
5052 | make-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 | |||
5069 | map-age-cleaner@^0.1.1: | 4400 | map-age-cleaner@^0.1.1: |
5070 | version "0.1.3" | 4401 | version "0.1.3" |
5071 | resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" | 4402 | resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" |
@@ -5085,10 +4416,10 @@ map-visit@^1.0.0: | |||
5085 | dependencies: | 4416 | dependencies: |
5086 | object-visit "^1.0.0" | 4417 | object-visit "^1.0.0" |
5087 | 4418 | ||
5088 | marked-man@^0.4.2: | 4419 | marked-man@^0.6.0: |
5089 | version "0.4.2" | 4420 | version "0.6.0" |
5090 | resolved "https://registry.yarnpkg.com/marked-man/-/marked-man-0.4.2.tgz#4507ee0bafa04f46f9b48082f62b3593c8d667bb" | 4421 | resolved "https://registry.yarnpkg.com/marked-man/-/marked-man-0.6.0.tgz#ac049f840cf633a0f679af58f321c7de3dd583d8" |
5091 | integrity sha512-4AMgee2zyjzgybboMBjAfDQ1ZUnBFDmxTKld7xuEc9N5tY3T7CqQYqYfKAkUc73tNLeOdwKcR3N5p1toXLiHAA== | 4422 | integrity sha512-lqzGe2uPo0KPO5J5yyfZ6PbEpZS6VIMHIzltXNzdwTNBysD0pNLtTaGrtT5R4aFT8UaVR3Fuz9rN3SEFYnea5Q== |
5092 | 4423 | ||
5093 | matcher@^1.0.0: | 4424 | matcher@^1.0.0: |
5094 | version "1.1.1" | 4425 | version "1.1.1" |
@@ -5106,11 +4437,6 @@ md5@^2.2.1: | |||
5106 | crypt "~0.0.1" | 4437 | crypt "~0.0.1" |
5107 | is-buffer "~1.1.1" | 4438 | is-buffer "~1.1.1" |
5108 | 4439 | ||
5109 | meant@~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 | |||
5114 | media-typer@0.3.0: | 4440 | media-typer@0.3.0: |
5115 | version "0.3.0" | 4441 | version "0.3.0" |
5116 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" | 4442 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" |
@@ -5125,13 +4451,6 @@ mediasource@^2.1.0, mediasource@^2.2.2: | |||
5125 | readable-stream "^3.0.0" | 4451 | readable-stream "^3.0.0" |
5126 | to-arraybuffer "^1.0.1" | 4452 | to-arraybuffer "^1.0.1" |
5127 | 4453 | ||
5128 | mem@^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 | |||
5135 | mem@^4.0.0: | 4454 | mem@^4.0.0: |
5136 | version "4.3.0" | 4455 | version "4.3.0" |
5137 | resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" | 4456 | resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" |
@@ -5175,7 +4494,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" | 4494 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" |
5176 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= | 4495 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= |
5177 | 4496 | ||
5178 | micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: | 4497 | micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: |
5179 | version "3.1.10" | 4498 | version "3.1.10" |
5180 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" | 4499 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" |
5181 | integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== | 4500 | integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== |
@@ -5194,37 +4513,32 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: | |||
5194 | snapdragon "^0.8.1" | 4513 | snapdragon "^0.8.1" |
5195 | to-regex "^3.0.2" | 4514 | to-regex "^3.0.2" |
5196 | 4515 | ||
5197 | mime-db@~1.38.0: | 4516 | mime-db@1.40.0: |
5198 | version "1.38.0" | 4517 | version "1.40.0" |
5199 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" | 4518 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" |
5200 | integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg== | 4519 | integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== |
5201 | 4520 | ||
5202 | mime-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: | 4521 | mime-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" | 4522 | version "2.1.24" |
5204 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd" | 4523 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" |
5205 | integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog== | 4524 | integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== |
5206 | dependencies: | 4525 | dependencies: |
5207 | mime-db "~1.38.0" | 4526 | mime-db "1.40.0" |
5208 | 4527 | ||
5209 | mime@1.3.4: | 4528 | mime@1.3.4: |
5210 | version "1.3.4" | 4529 | version "1.3.4" |
5211 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" | 4530 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" |
5212 | integrity sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM= | 4531 | integrity sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM= |
5213 | 4532 | ||
5214 | mime@1.4.1: | 4533 | mime@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 | |||
5219 | mime@^1.3.4, mime@^1.4.1: | ||
5220 | version "1.6.0" | 4534 | version "1.6.0" |
5221 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" | 4535 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" |
5222 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== | 4536 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== |
5223 | 4537 | ||
5224 | mime@^2.4.0: | 4538 | mime@^2.4.0: |
5225 | version "2.4.0" | 4539 | version "2.4.3" |
5226 | resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.0.tgz#e051fd881358585f3279df333fe694da0bcffdd6" | 4540 | resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.3.tgz#229687331e86f68924e6cb59e1cdd937f18275fe" |
5227 | integrity sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w== | 4541 | integrity sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw== |
5228 | 4542 | ||
5229 | mimelib@^0.3.0: | 4543 | mimelib@^0.3.0: |
5230 | version "0.3.1" | 4544 | version "0.3.1" |
@@ -5276,7 +4590,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" | 4590 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" |
5277 | integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= | 4591 | integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= |
5278 | 4592 | ||
5279 | minipass@^2.2.1, minipass@^2.3.4, minipass@^2.3.5: | 4593 | minipass@^2.2.1, minipass@^2.3.5: |
5280 | version "2.3.5" | 4594 | version "2.3.5" |
5281 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" | 4595 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" |
5282 | integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== | 4596 | integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== |
@@ -5284,29 +4598,13 @@ minipass@^2.2.1, minipass@^2.3.4, minipass@^2.3.5: | |||
5284 | safe-buffer "^5.1.2" | 4598 | safe-buffer "^5.1.2" |
5285 | yallist "^3.0.0" | 4599 | yallist "^3.0.0" |
5286 | 4600 | ||
5287 | minizlib@^1.1.1: | 4601 | minizlib@^1.2.1: |
5288 | version "1.2.1" | 4602 | version "1.2.1" |
5289 | resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" | 4603 | resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" |
5290 | integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== | 4604 | integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== |
5291 | dependencies: | 4605 | dependencies: |
5292 | minipass "^2.2.1" | 4606 | minipass "^2.2.1" |
5293 | 4607 | ||
5294 | mississippi@^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 | |||
5310 | mixin-deep@^1.2.0: | 4608 | mixin-deep@^1.2.0: |
5311 | version "1.3.1" | 4609 | version "1.3.1" |
5312 | resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" | 4610 | resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" |
@@ -5315,46 +4613,56 @@ mixin-deep@^1.2.0: | |||
5315 | for-in "^1.0.2" | 4613 | for-in "^1.0.2" |
5316 | is-extendable "^1.0.1" | 4614 | is-extendable "^1.0.1" |
5317 | 4615 | ||
5318 | mkdirp@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: | 4616 | mkdirp@0.5.1, mkdirp@0.x.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: |
5319 | version "0.5.1" | 4617 | version "0.5.1" |
5320 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" | 4618 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" |
5321 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= | 4619 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= |
5322 | dependencies: | 4620 | dependencies: |
5323 | minimist "0.0.8" | 4621 | minimist "0.0.8" |
5324 | 4622 | ||
4623 | mocha-parallel-tests@^2.1.0: | ||
4624 | version "2.1.2" | ||
4625 | resolved "https://registry.yarnpkg.com/mocha-parallel-tests/-/mocha-parallel-tests-2.1.2.tgz#2f5c24022257e5fc6c63a6bd22d49c1487496b26" | ||
4626 | integrity sha512-FatFg3MHLio9ir1oP6J0HNEo6R5344JC1y+We90iALdiT9F9xNPN0KbGXxRNlGlSl0GodfSESKbRzBvT9ctgIw== | ||
4627 | dependencies: | ||
4628 | circular-json "^0.5.9" | ||
4629 | debug "^4.1.1" | ||
4630 | uuid "^3.3.2" | ||
4631 | yargs "^13.2.2" | ||
4632 | |||
5325 | mocha@^6.0.0: | 4633 | mocha@^6.0.0: |
5326 | version "6.0.2" | 4634 | version "6.1.4" |
5327 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.0.2.tgz#cdc1a6fdf66472c079b5605bac59d29807702d2c" | 4635 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.1.4.tgz#e35fada242d5434a7e163d555c705f6875951640" |
5328 | integrity sha512-RtTJsmmToGyeTznSOMoM6TPEk1A84FQaHIciKrRqARZx+B5ccJ5tXlmJzEKGBxZdqk9UjpRsesZTUkZmR5YnuQ== | 4636 | integrity sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg== |
5329 | dependencies: | 4637 | dependencies: |
5330 | ansi-colors "3.2.3" | 4638 | ansi-colors "3.2.3" |
5331 | browser-stdout "1.3.1" | 4639 | browser-stdout "1.3.1" |
5332 | debug "3.2.6" | 4640 | debug "3.2.6" |
5333 | diff "3.5.0" | 4641 | diff "3.5.0" |
5334 | escape-string-regexp "1.0.5" | 4642 | escape-string-regexp "1.0.5" |
5335 | findup-sync "2.0.0" | 4643 | find-up "3.0.0" |
5336 | glob "7.1.3" | 4644 | glob "7.1.3" |
5337 | growl "1.10.5" | 4645 | growl "1.10.5" |
5338 | he "1.2.0" | 4646 | he "1.2.0" |
5339 | js-yaml "3.12.0" | 4647 | js-yaml "3.13.1" |
5340 | log-symbols "2.2.0" | 4648 | log-symbols "2.2.0" |
5341 | minimatch "3.0.4" | 4649 | minimatch "3.0.4" |
5342 | mkdirp "0.5.1" | 4650 | mkdirp "0.5.1" |
5343 | ms "2.1.1" | 4651 | ms "2.1.1" |
5344 | node-environment-flags "1.0.4" | 4652 | node-environment-flags "1.0.5" |
5345 | object.assign "4.1.0" | 4653 | object.assign "4.1.0" |
5346 | strip-json-comments "2.0.1" | 4654 | strip-json-comments "2.0.1" |
5347 | supports-color "6.0.0" | 4655 | supports-color "6.0.0" |
5348 | which "1.3.1" | 4656 | which "1.3.1" |
5349 | wide-align "1.1.3" | 4657 | wide-align "1.1.3" |
5350 | yargs "12.0.5" | 4658 | yargs "13.2.2" |
5351 | yargs-parser "11.1.1" | 4659 | yargs-parser "13.0.0" |
5352 | yargs-unparser "1.5.0" | 4660 | yargs-unparser "1.5.0" |
5353 | 4661 | ||
5354 | moment-timezone@^0.5.21, moment-timezone@^0.5.23: | 4662 | moment-timezone@^0.5.21, moment-timezone@^0.5.23: |
5355 | version "0.5.23" | 4663 | version "0.5.25" |
5356 | resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.23.tgz#7cbb00db2c14c71b19303cb47b0fb0a6d8651463" | 4664 | resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.25.tgz#a11bfa2f74e088327f2cd4c08b3e7bdf55957810" |
5357 | integrity sha512-WHFH85DkCfiNMDX5D3X7hpNH3/PUhjTGcD0U1SgfBGZxJ3qUmJh5FdvaFjcClxOvB3rzdfj4oRffbI38jEnC1w== | 4665 | integrity sha512-DgEaTyN/z0HFaVcVbSyVCUU6HeFdnNC3vE4c9cgu2dgMTvjBUBdBzWfasTBmAW45u5OIMeCJtU8yNjM22DHucw== |
5358 | dependencies: | 4666 | dependencies: |
5359 | moment ">= 2.9.0" | 4667 | moment ">= 2.9.0" |
5360 | 4668 | ||
@@ -5374,18 +4682,6 @@ morgan@^1.5.3: | |||
5374 | on-finished "~2.3.0" | 4682 | on-finished "~2.3.0" |
5375 | on-headers "~1.0.1" | 4683 | on-headers "~1.0.1" |
5376 | 4684 | ||
5377 | move-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 | |||
5389 | mp4-box-encoding@^1.1.0, mp4-box-encoding@^1.3.0: | 4685 | mp4-box-encoding@^1.1.0, mp4-box-encoding@^1.3.0: |
5390 | version "1.3.0" | 4686 | version "1.3.0" |
5391 | resolved "https://registry.yarnpkg.com/mp4-box-encoding/-/mp4-box-encoding-1.3.0.tgz#2a6f750947ff68c3a498fd76cd6424c53d995d48" | 4687 | resolved "https://registry.yarnpkg.com/mp4-box-encoding/-/mp4-box-encoding-1.3.0.tgz#2a6f750947ff68c3a498fd76cd6424c53d995d48" |
@@ -5421,7 +4717,7 @@ ms@2.0.0: | |||
5421 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" | 4717 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" |
5422 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= | 4718 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= |
5423 | 4719 | ||
5424 | ms@2.1.1, ms@^2.0.0, ms@^2.1.1: | 4720 | ms@2.1.1, ms@^2.1.1: |
5425 | version "2.1.1" | 4721 | version "2.1.1" |
5426 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" | 4722 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" |
5427 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== | 4723 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== |
@@ -5458,16 +4754,16 @@ mute-stream@~0.0.4: | |||
5458 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" | 4754 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" |
5459 | integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== | 4755 | integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== |
5460 | 4756 | ||
5461 | nan@2.13.1: | 4757 | nan@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 | |||
5466 | nan@^2.10.0, nan@^2.13.1, nan@^2.9.2: | ||
5467 | version "2.13.2" | 4758 | version "2.13.2" |
5468 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" | 4759 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" |
5469 | integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw== | 4760 | integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw== |
5470 | 4761 | ||
4762 | nan@^2.10.0, nan@^2.12.1, nan@^2.13.2: | ||
4763 | version "2.14.0" | ||
4764 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" | ||
4765 | integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== | ||
4766 | |||
5471 | nan@~2.10.0: | 4767 | nan@~2.10.0: |
5472 | version "2.10.0" | 4768 | version "2.10.0" |
5473 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" | 4769 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" |
@@ -5501,11 +4797,11 @@ ncp@1.0.x: | |||
5501 | integrity sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY= | 4797 | integrity sha1-0VNn5cuHQyuhF9K/gP30Wuz7QkY= |
5502 | 4798 | ||
5503 | needle@^2.2.1: | 4799 | needle@^2.2.1: |
5504 | version "2.2.4" | 4800 | version "2.4.0" |
5505 | resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" | 4801 | resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" |
5506 | integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== | 4802 | integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== |
5507 | dependencies: | 4803 | dependencies: |
5508 | debug "^2.1.2" | 4804 | debug "^3.2.6" |
5509 | iconv-lite "^0.4.4" | 4805 | iconv-lite "^0.4.4" |
5510 | sax "^1.2.4" | 4806 | sax "^1.2.4" |
5511 | 4807 | ||
@@ -5519,19 +4815,16 @@ negotiator@0.6.1: | |||
5519 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" | 4815 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" |
5520 | integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= | 4816 | integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= |
5521 | 4817 | ||
4818 | negotiator@0.6.2: | ||
4819 | version "0.6.2" | ||
4820 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" | ||
4821 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== | ||
4822 | |||
5522 | netmask@^1.0.6: | 4823 | netmask@^1.0.6: |
5523 | version "1.0.6" | 4824 | version "1.0.6" |
5524 | resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" | 4825 | resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" |
5525 | integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU= | 4826 | integrity sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU= |
5526 | 4827 | ||
5527 | netrc-parser@^3.1.6: | ||
5528 | version "3.1.6" | ||
5529 | resolved "https://registry.yarnpkg.com/netrc-parser/-/netrc-parser-3.1.6.tgz#7243c9ec850b8e805b9bdc7eae7b1450d4a96e72" | ||
5530 | integrity sha512-lY+fmkqSwntAAjfP63jB4z5p5WbuZwyMCD3pInT7dpHU/Gc6Vv90SAC6A0aNiqaRGHiuZFBtiwu+pu8W/Eyotw== | ||
5531 | dependencies: | ||
5532 | debug "^3.1.0" | ||
5533 | execa "^0.10.0" | ||
5534 | |||
5535 | next-event@^1.0.0: | 4828 | next-event@^1.0.0: |
5536 | version "1.0.0" | 4829 | version "1.0.0" |
5537 | resolved "https://registry.yarnpkg.com/next-event/-/next-event-1.0.0.tgz#e7778acde2e55802e0ad1879c39cf6f75eda61d8" | 4830 | resolved "https://registry.yarnpkg.com/next-event/-/next-event-1.0.0.tgz#e7778acde2e55802e0ad1879c39cf6f75eda61d8" |
@@ -5547,38 +4840,25 @@ nice-try@^1.0.4: | |||
5547 | resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" | 4840 | resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" |
5548 | integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== | 4841 | integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== |
5549 | 4842 | ||
5550 | nocache@2.0.0: | 4843 | nocache@2.1.0: |
5551 | version "2.0.0" | 4844 | version "2.1.0" |
5552 | resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.0.0.tgz#202b48021a0c4cbde2df80de15a17443c8b43980" | 4845 | resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" |
5553 | integrity sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA= | 4846 | integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q== |
5554 | 4847 | ||
5555 | node-abi@^2.7.0: | 4848 | node-abi@^2.7.0: |
5556 | version "2.7.1" | 4849 | version "2.8.0" |
5557 | resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.7.1.tgz#a8997ae91176a5fbaa455b194976e32683cda643" | 4850 | resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.8.0.tgz#bd2e88dbe6a6871e6dd08553e0605779325737ec" |
5558 | integrity sha512-OV8Bq1OrPh6z+Y4dqwo05HqrRL9YNF7QVMRfq1/pguwKLG+q9UB/Lk0x5qXjO23JjJg+/jqCHSTaG1P3tfKfuw== | 4851 | integrity sha512-1/aa2clS0pue0HjckL62CsbhWWU35HARvBDXcJtYKbYR7LnIutmpxmXbuDMV9kEviD2lP/wACOgWmmwljghHyQ== |
5559 | dependencies: | 4852 | dependencies: |
5560 | semver "^5.4.1" | 4853 | semver "^5.4.1" |
5561 | 4854 | ||
5562 | node-addon-api@^1.6.0: | 4855 | node-environment-flags@1.0.5: |
5563 | version "1.6.2" | 4856 | version "1.0.5" |
5564 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.2.tgz#d8aad9781a5cfc4132cc2fecdbdd982534265217" | 4857 | resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" |
5565 | integrity sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA== | 4858 | integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== |
5566 | |||
5567 | node-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: | 4859 | dependencies: |
5572 | object.getownpropertydescriptors "^2.0.3" | 4860 | object.getownpropertydescriptors "^2.0.3" |
5573 | 4861 | semver "^5.7.0" | |
5574 | node-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 | 4862 | ||
5583 | node-forge@^0.7.1: | 4863 | node-forge@^0.7.1: |
5584 | version "0.7.6" | 4864 | version "0.7.6" |
@@ -5590,25 +4870,7 @@ node-gyp-build@~3.7.0: | |||
5590 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d" | 4870 | resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d" |
5591 | integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w== | 4871 | integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w== |
5592 | 4872 | ||
5593 | node-gyp@^3.8.0: | 4873 | node-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 | |||
5611 | node-pre-gyp@0.12.0: | ||
5612 | version "0.12.0" | 4874 | version "0.12.0" |
5613 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" | 4875 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" |
5614 | integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== | 4876 | integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== |
@@ -5624,22 +4886,6 @@ node-pre-gyp@0.12.0: | |||
5624 | semver "^5.3.0" | 4886 | semver "^5.3.0" |
5625 | tar "^4" | 4887 | tar "^4" |
5626 | 4888 | ||
5627 | node-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 | |||
5643 | node-pre-gyp@~0.11.0: | 4889 | node-pre-gyp@~0.11.0: |
5644 | version "0.11.0" | 4890 | version "0.11.0" |
5645 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" | 4891 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" |
@@ -5681,16 +4927,16 @@ nodemailer-shared@^1.1.0: | |||
5681 | nodemailer-fetch "1.6.0" | 4927 | nodemailer-fetch "1.6.0" |
5682 | 4928 | ||
5683 | nodemailer@^6.0.0: | 4929 | nodemailer@^6.0.0: |
5684 | version "6.0.0" | 4930 | version "6.2.1" |
5685 | resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.0.0.tgz#d9761128771739dc87c1fdd747f569b7f135cb02" | 4931 | resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.2.1.tgz#20d773925eb8f7a06166a0b62c751dc8290429f3" |
5686 | integrity sha512-PMQJyLhoNAMoBU1hEh5aaUkpa/tcDNwzS7s7zow/myKfoEoZewMxUuWZqQ5yjYsAnvE484KSkYH5s6iPvcjhCg== | 4932 | integrity sha512-TagB7iuIi9uyNgHExo8lUDq3VK5/B0BpbkcjIgNvxbtVrjNqq0DwAOTuzALPVkK76kMhTSzIgHqg8X1uklVs6g== |
5687 | 4933 | ||
5688 | nodemon@^1.18.6: | 4934 | nodemon@^1.18.6: |
5689 | version "1.18.10" | 4935 | version "1.19.1" |
5690 | resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.10.tgz#3ba63f64eb4c283cf3e4f75f30817e9d4f393afe" | 4936 | resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.19.1.tgz#576f0aad0f863aabf8c48517f6192ff987cd5071" |
5691 | integrity sha512-we51yBb1TfEvZamFchRgcfLbVYgg0xlGbyXmOtbBzDwxwgewYS/YbZ5tnlnsH51+AoSTTsT3A2E/FloUbtH8cQ== | 4937 | integrity sha512-/DXLzd/GhiaDXXbGId5BzxP1GlsqtMGM9zTmkWrgXtSqjKmGSbLicM/oAy4FR0YWm14jCHRwnR31AHS2dYFHrg== |
5692 | dependencies: | 4938 | dependencies: |
5693 | chokidar "^2.1.0" | 4939 | chokidar "^2.1.5" |
5694 | debug "^3.1.0" | 4940 | debug "^3.1.0" |
5695 | ignore-by-default "^1.0.1" | 4941 | ignore-by-default "^1.0.1" |
5696 | minimatch "^3.0.4" | 4942 | minimatch "^3.0.4" |
@@ -5706,14 +4952,7 @@ noop-logger@^0.1.1: | |||
5706 | resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" | 4952 | resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" |
5707 | integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= | 4953 | integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= |
5708 | 4954 | ||
5709 | "nopt@2 || 3": | 4955 | nopt@^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 | |||
5716 | nopt@^4.0.1, nopt@~4.0.1: | ||
5717 | version "4.0.1" | 4956 | version "4.0.1" |
5718 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" | 4957 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" |
5719 | integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= | 4958 | integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= |
@@ -5728,7 +4967,7 @@ nopt@~1.0.10: | |||
5728 | dependencies: | 4967 | dependencies: |
5729 | abbrev "1" | 4968 | abbrev "1" |
5730 | 4969 | ||
5731 | normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.4.0, normalize-package-data@^2.5.0: | 4970 | normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: |
5732 | version "2.5.0" | 4971 | version "2.5.0" |
5733 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" | 4972 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" |
5734 | integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== | 4973 | integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== |
@@ -5750,61 +4989,12 @@ normalize-path@^3.0.0: | |||
5750 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" | 4989 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" |
5751 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== | 4990 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== |
5752 | 4991 | ||
5753 | npm-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 | |||
5761 | npm-bundled@^1.0.1: | 4992 | npm-bundled@^1.0.1: |
5762 | version "1.0.6" | 4993 | version "1.0.6" |
5763 | resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" | 4994 | resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" |
5764 | integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== | 4995 | integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== |
5765 | 4996 | ||
5766 | npm-cache-filename@~1.0.2: | 4997 | npm-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 | |||
5771 | npm-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 | |||
5778 | npm-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 | |||
5792 | npm-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 | |||
5807 | npm-packlist@^1.1.12, npm-packlist@^1.1.6, npm-packlist@^1.4.1: | ||
5808 | version "1.4.1" | 4998 | version "1.4.1" |
5809 | resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" | 4999 | resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" |
5810 | integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw== | 5000 | integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw== |
@@ -5819,36 +5009,6 @@ npm-path@^2.0.2: | |||
5819 | dependencies: | 5009 | dependencies: |
5820 | which "^1.2.10" | 5010 | which "^1.2.10" |
5821 | 5011 | ||
5822 | npm-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 | |||
5831 | npm-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 | |||
5840 | npm-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 | |||
5852 | npm-run-path@^2.0.0: | 5012 | npm-run-path@^2.0.0: |
5853 | version "2.0.2" | 5013 | version "2.0.2" |
5854 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" | 5014 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" |
@@ -5856,11 +5016,6 @@ npm-run-path@^2.0.0: | |||
5856 | dependencies: | 5016 | dependencies: |
5857 | path-key "^2.0.0" | 5017 | path-key "^2.0.0" |
5858 | 5018 | ||
5859 | npm-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 | |||
5864 | npm-which@^3.0.1: | 5019 | npm-which@^3.0.1: |
5865 | version "3.0.1" | 5020 | version "3.0.1" |
5866 | resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa" | 5021 | resolved "https://registry.yarnpkg.com/npm-which/-/npm-which-3.0.1.tgz#9225f26ec3a285c209cae67c3b11a6b4ab7140aa" |
@@ -5870,121 +5025,7 @@ npm-which@^3.0.1: | |||
5870 | npm-path "^2.0.2" | 5025 | npm-path "^2.0.2" |
5871 | which "^1.2.10" | 5026 | which "^1.2.10" |
5872 | 5027 | ||
5873 | npm@*: | 5028 | npmlog@^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" | 5029 | version "4.1.2" |
5989 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" | 5030 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" |
5990 | integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== | 5031 | integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== |
@@ -6041,9 +5082,9 @@ object-copy@^0.1.0: | |||
6041 | kind-of "^3.0.3" | 5082 | kind-of "^3.0.3" |
6042 | 5083 | ||
6043 | object-keys@^1.0.11, object-keys@^1.0.12: | 5084 | object-keys@^1.0.11, object-keys@^1.0.12: |
6044 | version "1.1.0" | 5085 | version "1.1.1" |
6045 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.0.tgz#11bd22348dd2e096a045ab06f6c85bcc340fa032" | 5086 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" |
6046 | integrity sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg== | 5087 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== |
6047 | 5088 | ||
6048 | object-visit@^1.0.0: | 5089 | object-visit@^1.0.0: |
6049 | version "1.0.1" | 5090 | version "1.0.1" |
@@ -6089,7 +5130,7 @@ on-headers@~1.0.1: | |||
6089 | resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" | 5130 | 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== | 5131 | integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== |
6091 | 5132 | ||
6092 | once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0, once@~1.4.0: | 5133 | once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: |
6093 | version "1.4.0" | 5134 | version "1.4.0" |
6094 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" | 5135 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" |
6095 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= | 5136 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= |
@@ -6134,11 +5175,6 @@ openapi-schema-validation@^0.4.2: | |||
6134 | jsonschema-draft4 "^1.0.0" | 5175 | jsonschema-draft4 "^1.0.0" |
6135 | swagger-schema-official "2.0.0-bab6bed" | 5176 | swagger-schema-official "2.0.0-bab6bed" |
6136 | 5177 | ||
6137 | opener@^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 | |||
6142 | optionator@^0.8.1: | 5178 | optionator@^0.8.1: |
6143 | version "0.8.2" | 5179 | version "0.8.2" |
6144 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" | 5180 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" |
@@ -6161,16 +5197,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" | 5197 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" |
6162 | integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= | 5198 | integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= |
6163 | 5199 | ||
6164 | os-locale@^2.0.0: | 5200 | os-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 | |||
6173 | os-locale@^3.0.0: | ||
6174 | version "3.1.0" | 5201 | version "3.1.0" |
6175 | resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" | 5202 | resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" |
6176 | integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== | 5203 | integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== |
@@ -6184,7 +5211,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" | 5211 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" |
6185 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= | 5212 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= |
6186 | 5213 | ||
6187 | osenv@0, osenv@^0.1.4, osenv@^0.1.5: | 5214 | osenv@^0.1.4: |
6188 | version "0.1.5" | 5215 | version "0.1.5" |
6189 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" | 5216 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" |
6190 | integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== | 5217 | integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== |
@@ -6203,31 +5230,17 @@ p-finally@^1.0.0: | |||
6203 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= | 5230 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= |
6204 | 5231 | ||
6205 | p-is-promise@^2.0.0: | 5232 | p-is-promise@^2.0.0: |
6206 | version "2.0.0" | 5233 | version "2.1.0" |
6207 | resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5" | 5234 | resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" |
6208 | integrity sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg== | 5235 | integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== |
6209 | |||
6210 | p-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 | 5236 | ||
6217 | p-limit@^2.0.0: | 5237 | p-limit@^2.0.0, p-limit@^2.2.0: |
6218 | version "2.2.0" | 5238 | version "2.2.0" |
6219 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" | 5239 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" |
6220 | integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== | 5240 | integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== |
6221 | dependencies: | 5241 | dependencies: |
6222 | p-try "^2.0.0" | 5242 | p-try "^2.0.0" |
6223 | 5243 | ||
6224 | p-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 | |||
6231 | p-locate@^3.0.0: | 5244 | p-locate@^3.0.0: |
6232 | version "3.0.0" | 5245 | version "3.0.0" |
6233 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" | 5246 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" |
@@ -6235,28 +5248,30 @@ p-locate@^3.0.0: | |||
6235 | dependencies: | 5248 | dependencies: |
6236 | p-limit "^2.0.0" | 5249 | p-limit "^2.0.0" |
6237 | 5250 | ||
5251 | p-locate@^4.1.0: | ||
5252 | version "4.1.0" | ||
5253 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" | ||
5254 | integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== | ||
5255 | dependencies: | ||
5256 | p-limit "^2.2.0" | ||
5257 | |||
6238 | p-map@^1.1.1: | 5258 | p-map@^1.1.1: |
6239 | version "1.2.0" | 5259 | version "1.2.0" |
6240 | resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" | 5260 | resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" |
6241 | integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== | 5261 | integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== |
6242 | 5262 | ||
6243 | p-map@^2.0.0: | 5263 | p-map@^2.0.0: |
6244 | version "2.0.0" | 5264 | version "2.1.0" |
6245 | resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.0.0.tgz#be18c5a5adeb8e156460651421aceca56c213a50" | 5265 | resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" |
6246 | integrity sha512-GO107XdrSUmtHxVoi60qc9tUl/KkNKm+X2CF4P9amalpGxv5YqVPJNfSb0wcA+syCopkZvYYIzW8OVTQW59x/w== | 5266 | integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== |
6247 | 5267 | ||
6248 | p-timeout@^2.0.1: | 5268 | p-timeout@^3.1.0: |
6249 | version "2.0.1" | 5269 | version "3.1.0" |
6250 | resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" | 5270 | resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.1.0.tgz#198c1f503bb973e9b9727177a276c80afd6851f3" |
6251 | integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== | 5271 | integrity sha512-C27DYI+tCroT8J8cTEyySGydl2B7FlxrGNF5/wmMbl1V+jeehUCzEE/BVgzRebdm2K3ZitKOKx8YbdFumDyYmw== |
6252 | dependencies: | 5272 | dependencies: |
6253 | p-finally "^1.0.0" | 5273 | p-finally "^1.0.0" |
6254 | 5274 | ||
6255 | p-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 | |||
6260 | p-try@^2.0.0: | 5275 | p-try@^2.0.0: |
6261 | version "2.2.0" | 5276 | version "2.2.0" |
6262 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" | 5277 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" |
@@ -6284,48 +5299,6 @@ packet-reader@1.0.0: | |||
6284 | resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" | 5299 | resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" |
6285 | integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== | 5300 | integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== |
6286 | 5301 | ||
6287 | pacote@^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 | |||
6320 | parallel-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 | |||
6329 | parse-json@^4.0.0: | 5302 | parse-json@^4.0.0: |
6330 | version "4.0.0" | 5303 | version "4.0.0" |
6331 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" | 5304 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" |
@@ -6339,11 +5312,6 @@ parse-numeric-range@^0.0.2: | |||
6339 | resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4" | 5312 | resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-0.0.2.tgz#b4f09d413c7adbcd987f6e9233c7b4b210c938e4" |
6340 | integrity sha1-tPCdQTx6282Yf26SM8e0shDJOOQ= | 5313 | integrity sha1-tPCdQTx6282Yf26SM8e0shDJOOQ= |
6341 | 5314 | ||
6342 | parse-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 | |||
6347 | parse-torrent@^6.0.0, parse-torrent@^6.1.2: | 5315 | parse-torrent@^6.0.0, parse-torrent@^6.1.2: |
6348 | version "6.1.2" | 5316 | version "6.1.2" |
6349 | resolved "https://registry.yarnpkg.com/parse-torrent/-/parse-torrent-6.1.2.tgz#99da5bdd23435a1cb7e8e7a63847c4efb21b1956" | 5317 | resolved "https://registry.yarnpkg.com/parse-torrent/-/parse-torrent-6.1.2.tgz#99da5bdd23435a1cb7e8e7a63847c4efb21b1956" |
@@ -6378,10 +5346,10 @@ parseuri@0.0.5: | |||
6378 | dependencies: | 5346 | dependencies: |
6379 | better-assert "~1.0.0" | 5347 | better-assert "~1.0.0" |
6380 | 5348 | ||
6381 | parseurl@~1.3.1, parseurl@~1.3.2: | 5349 | parseurl@~1.3.1, parseurl@~1.3.3: |
6382 | version "1.3.2" | 5350 | version "1.3.3" |
6383 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" | 5351 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" |
6384 | integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= | 5352 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== |
6385 | 5353 | ||
6386 | pascalcase@^0.1.1: | 5354 | pascalcase@^0.1.1: |
6387 | version "0.1.1" | 5355 | version "0.1.1" |
@@ -6410,7 +5378,7 @@ path-is-absolute@^1.0.0: | |||
6410 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" | 5378 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" |
6411 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= | 5379 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= |
6412 | 5380 | ||
6413 | path-is-inside@^1.0.1, path-is-inside@^1.0.2, path-is-inside@~1.0.2: | 5381 | path-is-inside@^1.0.1, path-is-inside@^1.0.2: |
6414 | version "1.0.2" | 5382 | version "1.0.2" |
6415 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" | 5383 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" |
6416 | integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= | 5384 | integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= |
@@ -6482,20 +5450,20 @@ pg-pool@^2.0.4: | |||
6482 | integrity sha512-hod2zYQxM8Gt482q+qONGTYcg/qVcV32VHVPtktbBJs0us3Dj7xibISw0BAAXVMCzt8A/jhfJvpZaxUlqtqs0g== | 5450 | integrity sha512-hod2zYQxM8Gt482q+qONGTYcg/qVcV32VHVPtktbBJs0us3Dj7xibISw0BAAXVMCzt8A/jhfJvpZaxUlqtqs0g== |
6483 | 5451 | ||
6484 | pg-types@~2.0.0: | 5452 | pg-types@~2.0.0: |
6485 | version "2.0.0" | 5453 | version "2.0.1" |
6486 | resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.0.0.tgz#038ddc302a0340efcdb46d0581cc7caa2303cbba" | 5454 | resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.0.1.tgz#b8585a37f2a9c7b386747e44574799549e5f4933" |
6487 | integrity sha512-THUD7gQll5tys+5eQ8Rvs7DjHiIC3bLqixk3gMN9Hu8UrCBAOjf35FoI39rTGGc3lM2HU/R+Knpxvd11mCwOMA== | 5455 | integrity sha512-b7y6QM1VF5nOeX9ukMQ0h8a9z89mojrBHXfJeSug4mhL0YpxNBm83ot2TROyoAmX/ZOX3UbwVO4EbH7i1ZZNiw== |
6488 | dependencies: | 5456 | dependencies: |
6489 | pg-int8 "1.0.1" | 5457 | pg-int8 "1.0.1" |
6490 | postgres-array "~2.0.0" | 5458 | postgres-array "~2.0.0" |
6491 | postgres-bytea "~1.0.0" | 5459 | postgres-bytea "~1.0.0" |
6492 | postgres-date "~1.0.0" | 5460 | postgres-date "~1.0.4" |
6493 | postgres-interval "^1.1.0" | 5461 | postgres-interval "^1.1.0" |
6494 | 5462 | ||
6495 | pg@^7.4.1: | 5463 | pg@^7.4.1: |
6496 | version "7.9.0" | 5464 | version "7.11.0" |
6497 | resolved "https://registry.yarnpkg.com/pg/-/pg-7.9.0.tgz#04f0024d810544463f47dbb5aada2486aa7dcc36" | 5465 | resolved "https://registry.yarnpkg.com/pg/-/pg-7.11.0.tgz#a8b9ae9cf19199b7952b72957573d0a9c5e67c0c" |
6498 | integrity sha512-GkzteBFpsIoIBCSuomqik3IGvhqAtTr32jclR24RmUg170Jrn6ypwR97YalFHrsE1iaW8T0aAH13dmij8QUQ0g== | 5466 | integrity sha512-YO4V7vCmEMGoF390LJaFaohWNKaA2ayoQOEZmiHVcAUF+YsRThpf/TaKCgSvsSE7cDm37Q/Cy3Gz41xiX/XjTw== |
6499 | dependencies: | 5467 | dependencies: |
6500 | buffer-writer "2.0.0" | 5468 | buffer-writer "2.0.0" |
6501 | packet-reader "1.0.0" | 5469 | packet-reader "1.0.0" |
@@ -6541,12 +5509,12 @@ pinkie@^2.0.0: | |||
6541 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" | 5509 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" |
6542 | integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= | 5510 | integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= |
6543 | 5511 | ||
6544 | pkg-dir@^3.0.0: | 5512 | pkg-dir@^4.1.0: |
6545 | version "3.0.0" | 5513 | version "4.2.0" |
6546 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" | 5514 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" |
6547 | integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== | 5515 | integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== |
6548 | dependencies: | 5516 | dependencies: |
6549 | find-up "^3.0.0" | 5517 | find-up "^4.0.0" |
6550 | 5518 | ||
6551 | pkginfo@0.3.x: | 5519 | pkginfo@0.3.x: |
6552 | version "0.3.1" | 5520 | version "0.3.1" |
@@ -6590,10 +5558,10 @@ postgres-bytea@~1.0.0: | |||
6590 | resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" | 5558 | resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" |
6591 | integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= | 5559 | integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= |
6592 | 5560 | ||
6593 | postgres-date@~1.0.0: | 5561 | postgres-date@~1.0.4: |
6594 | version "1.0.3" | 5562 | version "1.0.4" |
6595 | resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.3.tgz#e2d89702efdb258ff9d9cee0fe91bd06975257a8" | 5563 | resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.4.tgz#1c2728d62ef1bff49abdd35c1f86d4bdf118a728" |
6596 | integrity sha1-4tiXAu/bJY/52c7g/pG9BpdSV6g= | 5564 | integrity sha512-bESRvKVuTrjoBluEcpv2346+6kgB7UlnqWZsnbnCccTNq/pqfj1j6oBaN5+b/NrDXepYUT/HKadqv3iS9lJuVA== |
6597 | 5565 | ||
6598 | postgres-interval@^1.1.0: | 5566 | postgres-interval@^1.1.0: |
6599 | version "1.2.0" | 5567 | version "1.2.0" |
@@ -6602,10 +5570,10 @@ postgres-interval@^1.1.0: | |||
6602 | dependencies: | 5570 | dependencies: |
6603 | xtend "^4.0.0" | 5571 | xtend "^4.0.0" |
6604 | 5572 | ||
6605 | prebuild-install@^5.2.5: | 5573 | prebuild-install@^5.3.0: |
6606 | version "5.2.5" | 5574 | version "5.3.0" |
6607 | resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.2.5.tgz#c7485911fe98950b7f7cd15bb9daee11b875cc44" | 5575 | resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.0.tgz#58b4d8344e03590990931ee088dd5401b03004c8" |
6608 | integrity sha512-6uZgMVg7yDfqlP5CPurVhtq3hUKBFNufiar4J5hZrlHTo59DDBEtyxw01xCdFss9j0Zb9+qzFVf/s4niayba3w== | 5576 | integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg== |
6609 | dependencies: | 5577 | dependencies: |
6610 | detect-libc "^1.0.3" | 5578 | detect-libc "^1.0.3" |
6611 | expand-template "^2.0.3" | 5579 | expand-template "^2.0.3" |
@@ -6644,19 +5612,6 @@ progress@^1.1.8: | |||
6644 | resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" | 5612 | resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" |
6645 | integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74= | 5613 | integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74= |
6646 | 5614 | ||
6647 | promise-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 | |||
6652 | promise-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 | |||
6660 | promise.prototype.finally@^3.1.0: | 5615 | promise.prototype.finally@^3.1.0: |
6661 | version "3.1.0" | 5616 | version "3.1.0" |
6662 | resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e" | 5617 | resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.0.tgz#66f161b1643636e50e7cf201dc1b84a857f3864e" |
@@ -6687,30 +5642,11 @@ prompt@^1.0.0: | |||
6687 | utile "0.3.x" | 5642 | utile "0.3.x" |
6688 | winston "2.1.x" | 5643 | winston "2.1.x" |
6689 | 5644 | ||
6690 | promzard@^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 | |||
6697 | property-expr@^1.5.0: | 5645 | property-expr@^1.5.0: |
6698 | version "1.5.1" | 5646 | version "1.5.1" |
6699 | resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f" | 5647 | resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f" |
6700 | integrity sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g== | 5648 | integrity sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g== |
6701 | 5649 | ||
6702 | proto-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 | |||
6707 | protoduck@^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 | |||
6714 | proxy-addr@~1.0.10: | 5650 | proxy-addr@~1.0.10: |
6715 | version "1.0.10" | 5651 | version "1.0.10" |
6716 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.0.10.tgz#0d40a82f801fc355567d2ecb65efe3f077f121c5" | 5652 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.0.10.tgz#0d40a82f801fc355567d2ecb65efe3f077f121c5" |
@@ -6719,18 +5655,13 @@ proxy-addr@~1.0.10: | |||
6719 | forwarded "~0.1.0" | 5655 | forwarded "~0.1.0" |
6720 | ipaddr.js "1.0.5" | 5656 | ipaddr.js "1.0.5" |
6721 | 5657 | ||
6722 | proxy-addr@~2.0.4: | 5658 | proxy-addr@~2.0.5: |
6723 | version "2.0.4" | 5659 | version "2.0.5" |
6724 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" | 5660 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" |
6725 | integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== | 5661 | integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== |
6726 | dependencies: | 5662 | dependencies: |
6727 | forwarded "~0.1.2" | 5663 | forwarded "~0.1.2" |
6728 | ipaddr.js "1.8.0" | 5664 | ipaddr.js "1.9.0" |
6729 | |||
6730 | prr@~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 | 5665 | ||
6735 | pseudomap@^1.0.2: | 5666 | pseudomap@^1.0.2: |
6736 | version "1.0.2" | 5667 | version "1.0.2" |
@@ -6738,14 +5669,14 @@ pseudomap@^1.0.2: | |||
6738 | integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= | 5669 | integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= |
6739 | 5670 | ||
6740 | psl@^1.1.24: | 5671 | psl@^1.1.24: |
6741 | version "1.1.31" | 5672 | version "1.1.32" |
6742 | resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" | 5673 | resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.32.tgz#3f132717cf2f9c169724b2b6caf373cf694198db" |
6743 | integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== | 5674 | integrity sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g== |
6744 | 5675 | ||
6745 | pstree.remy@^1.1.6: | 5676 | pstree.remy@^1.1.6: |
6746 | version "1.1.6" | 5677 | version "1.1.7" |
6747 | resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.6.tgz#73a55aad9e2d95814927131fbf4dc1b62d259f47" | 5678 | resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.7.tgz#c76963a28047ed61542dc361aa26ee55a7fa15f3" |
6748 | integrity sha512-NdF35+QsqD7EgNEI5mkI/X+UwaxVEbQaz9f4IooEmMUv6ZPmlTQYGjBPJGgrlzNdjSvIy4MWMg6Q6vCgBO2K+w== | 5679 | integrity sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A== |
6749 | 5680 | ||
6750 | pump@^1.0.0: | 5681 | pump@^1.0.0: |
6751 | version "1.0.3" | 5682 | version "1.0.3" |
@@ -6790,44 +5721,25 @@ punycode@^2.1.0: | |||
6790 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" | 5721 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" |
6791 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== | 5722 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== |
6792 | 5723 | ||
6793 | qrcode-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 | |||
6798 | qs@4.0.0: | 5724 | qs@4.0.0: |
6799 | version "4.0.0" | 5725 | version "4.0.0" |
6800 | resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" | 5726 | resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" |
6801 | integrity sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc= | 5727 | integrity sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc= |
6802 | 5728 | ||
6803 | qs@6.5.2, qs@~6.5.2: | 5729 | qs@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 | |||
6808 | qs@^6.5.1: | ||
6809 | version "6.7.0" | 5730 | version "6.7.0" |
6810 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" | 5731 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" |
6811 | integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== | 5732 | integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== |
6812 | 5733 | ||
6813 | query-string@^6.2.0: | 5734 | qs@~6.5.2: |
6814 | version "6.4.2" | 5735 | version "6.5.2" |
6815 | resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.4.2.tgz#8be1dbd105306aebf86022144f575a29d516b713" | 5736 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" |
6816 | integrity sha512-DfJqAen17LfLA3rQ+H5S4uXphrF+ANU1lT2ijds4V/Tj4gZxA3gx5/tg1bz7kYCmwna7LyJNCYqO7jNRzo3aLw== | 5737 | 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 | |||
6822 | qw@~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 | 5738 | ||
6827 | random-access-file@^2.0.1: | 5739 | random-access-file@^2.0.1: |
6828 | version "2.1.0" | 5740 | version "2.1.2" |
6829 | resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-2.1.0.tgz#7b3b6623d47e2f89282e77f0c9c9ae6da3cd9039" | 5741 | resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-2.1.2.tgz#eeb32e50b9831f32060516862381152ae4e05aa6" |
6830 | integrity sha512-W2hY3DboLETMclybTVzyqCNVKx1MjqUwZPzkpkkMD2t9mbGEtkV2SKWPqAJ/FTrAtnWB7aGwl0NDUS82da0KdQ== | 5742 | integrity sha512-dZo7HEcEPbZ/6XLXC4GXypiWvFbXVkdeMrJTi0B94pBJwddt/AvJh8GaQhso6KGYROGYCI/VWdHbmRDtkwT9pQ== |
6831 | dependencies: | 5743 | dependencies: |
6832 | mkdirp "^0.5.1" | 5744 | mkdirp "^0.5.1" |
6833 | random-access-storage "^1.1.1" | 5745 | random-access-storage "^1.1.1" |
@@ -6851,10 +5763,10 @@ randombytes@^2.0.3, randombytes@^2.0.5: | |||
6851 | dependencies: | 5763 | dependencies: |
6852 | safe-buffer "^5.1.0" | 5764 | safe-buffer "^5.1.0" |
6853 | 5765 | ||
6854 | range-parser@^1.2.0, range-parser@~1.2.0: | 5766 | range-parser@^1.2.0, range-parser@~1.2.1: |
6855 | version "1.2.0" | 5767 | version "1.2.1" |
6856 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" | 5768 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" |
6857 | integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= | 5769 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== |
6858 | 5770 | ||
6859 | range-parser@~1.0.3: | 5771 | range-parser@~1.0.3: |
6860 | version "1.0.3" | 5772 | version "1.0.3" |
@@ -6868,14 +5780,14 @@ range-slice-stream@^2.0.0: | |||
6868 | dependencies: | 5780 | dependencies: |
6869 | readable-stream "^3.0.2" | 5781 | readable-stream "^3.0.2" |
6870 | 5782 | ||
6871 | raw-body@2.3.3: | 5783 | raw-body@2.4.0: |
6872 | version "2.3.3" | 5784 | version "2.4.0" |
6873 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" | 5785 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" |
6874 | integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== | 5786 | integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== |
6875 | dependencies: | 5787 | dependencies: |
6876 | bytes "3.0.0" | 5788 | bytes "3.1.0" |
6877 | http-errors "1.6.3" | 5789 | http-errors "1.7.2" |
6878 | iconv-lite "0.4.23" | 5790 | iconv-lite "0.4.24" |
6879 | unpipe "1.0.0" | 5791 | unpipe "1.0.0" |
6880 | 5792 | ||
6881 | rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: | 5793 | rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: |
@@ -6898,50 +5810,6 @@ rdf-canonize@^0.2.1: | |||
6898 | node-forge "^0.7.1" | 5810 | node-forge "^0.7.1" |
6899 | semver "^5.4.1" | 5811 | semver "^5.4.1" |
6900 | 5812 | ||
6901 | read-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 | |||
6908 | read-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 | |||
6934 | read-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 | |||
6945 | read-pkg@^4.0.1: | 5813 | read-pkg@^4.0.1: |
6946 | version "4.0.1" | 5814 | version "4.0.1" |
6947 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" | 5815 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237" |
@@ -6951,27 +5819,24 @@ read-pkg@^4.0.1: | |||
6951 | parse-json "^4.0.0" | 5819 | parse-json "^4.0.0" |
6952 | pify "^3.0.0" | 5820 | pify "^3.0.0" |
6953 | 5821 | ||
6954 | read@1, read@1.0.x, read@~1.0.1, read@~1.0.7: | 5822 | read-pkg@^5.1.1: |
5823 | version "5.1.1" | ||
5824 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.1.1.tgz#5cf234dde7a405c90c88a519ab73c467e9cb83f5" | ||
5825 | integrity sha512-dFcTLQi6BZ+aFUaICg7er+/usEoqFdQxiEBsEMNGoipenihtxxtdrQuBXvyANCEI8VuUIVYFgeHGx9sLLvim4w== | ||
5826 | dependencies: | ||
5827 | "@types/normalize-package-data" "^2.4.0" | ||
5828 | normalize-package-data "^2.5.0" | ||
5829 | parse-json "^4.0.0" | ||
5830 | type-fest "^0.4.1" | ||
5831 | |||
5832 | read@1.0.x: | ||
6955 | version "1.0.7" | 5833 | version "1.0.7" |
6956 | resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" | 5834 | resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" |
6957 | integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= | 5835 | integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= |
6958 | dependencies: | 5836 | dependencies: |
6959 | mute-stream "~0.0.4" | 5837 | mute-stream "~0.0.4" |
6960 | 5838 | ||
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: | 5839 | readable-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 | |||
6974 | readable-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" | 5840 | version "1.1.14" |
6976 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" | 5841 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" |
6977 | integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= | 5842 | integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= |
@@ -6991,10 +5856,23 @@ readable-stream@1.1.x, "readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1 | |||
6991 | isarray "0.0.1" | 5856 | isarray "0.0.1" |
6992 | string_decoder "~0.10.x" | 5857 | string_decoder "~0.10.x" |
6993 | 5858 | ||
5859 | 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.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: | ||
5860 | version "2.3.6" | ||
5861 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" | ||
5862 | integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== | ||
5863 | dependencies: | ||
5864 | core-util-is "~1.0.0" | ||
5865 | inherits "~2.0.3" | ||
5866 | isarray "~1.0.0" | ||
5867 | process-nextick-args "~2.0.0" | ||
5868 | safe-buffer "~5.1.1" | ||
5869 | string_decoder "~1.1.1" | ||
5870 | util-deprecate "~1.0.1" | ||
5871 | |||
6994 | readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1: | 5872 | readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1: |
6995 | version "3.3.0" | 5873 | version "3.4.0" |
6996 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.3.0.tgz#cb8011aad002eb717bf040291feba8569c986fb9" | 5874 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" |
6997 | integrity sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw== | 5875 | integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== |
6998 | dependencies: | 5876 | dependencies: |
6999 | inherits "^2.0.3" | 5877 | inherits "^2.0.3" |
7000 | string_decoder "^1.1.1" | 5878 | string_decoder "^1.1.1" |
@@ -7007,16 +5885,6 @@ readable-wrap@^1.0.0: | |||
7007 | dependencies: | 5885 | dependencies: |
7008 | readable-stream "^1.1.13-1" | 5886 | readable-stream "^1.1.13-1" |
7009 | 5887 | ||
7010 | readdir-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 | |||
7020 | readdirp@^2.2.1: | 5888 | readdirp@^2.2.1: |
7021 | version "2.2.1" | 5889 | version "2.2.1" |
7022 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" | 5890 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" |
@@ -7040,11 +5908,16 @@ record-cache@^1.0.2: | |||
7040 | resolved "https://registry.yarnpkg.com/record-cache/-/record-cache-1.1.0.tgz#f8a467a691a469584b26e88d36b18afdb3932037" | 5908 | resolved "https://registry.yarnpkg.com/record-cache/-/record-cache-1.1.0.tgz#f8a467a691a469584b26e88d36b18afdb3932037" |
7041 | integrity sha512-u8rbtLEJV7HRacl/ZYwSBFD8NFyB3PfTTfGLP37IW3hftQCwu6z4Q2RLyxo1YJUNRTEzJfpLpGwVuEYdaIkG9Q== | 5909 | integrity sha512-u8rbtLEJV7HRacl/ZYwSBFD8NFyB3PfTTfGLP37IW3hftQCwu6z4Q2RLyxo1YJUNRTEzJfpLpGwVuEYdaIkG9Q== |
7042 | 5910 | ||
7043 | redis-commands@1.4.0, redis-commands@^1.2.0: | 5911 | redis-commands@1.4.0: |
7044 | version "1.4.0" | 5912 | version "1.4.0" |
7045 | resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.4.0.tgz#52f9cf99153efcce56a8f86af986bd04e988602f" | 5913 | resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.4.0.tgz#52f9cf99153efcce56a8f86af986bd04e988602f" |
7046 | integrity sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw== | 5914 | integrity sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw== |
7047 | 5915 | ||
5916 | redis-commands@^1.2.0: | ||
5917 | version "1.5.0" | ||
5918 | resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.5.0.tgz#80d2e20698fe688f227127ff9e5164a7dd17e785" | ||
5919 | integrity sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg== | ||
5920 | |||
7048 | redis-errors@^1.0.0, redis-errors@^1.2.0: | 5921 | redis-errors@^1.0.0, redis-errors@^1.2.0: |
7049 | version "1.2.0" | 5922 | version "1.2.0" |
7050 | resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" | 5923 | resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" |
@@ -7071,20 +5944,20 @@ redis@^2.8.0: | |||
7071 | redis-commands "^1.2.0" | 5944 | redis-commands "^1.2.0" |
7072 | redis-parser "^2.6.0" | 5945 | redis-parser "^2.6.0" |
7073 | 5946 | ||
7074 | referrer-policy@1.1.0: | 5947 | referrer-policy@1.2.0: |
7075 | version "1.1.0" | 5948 | version "1.2.0" |
7076 | resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.1.0.tgz#35774eb735bf50fb6c078e83334b472350207d79" | 5949 | resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.2.0.tgz#b99cfb8b57090dc454895ef897a4cc35ef67a98e" |
7077 | integrity sha1-NXdOtzW/UPtsB46DM0tHI1AgfXk= | 5950 | integrity sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA== |
7078 | 5951 | ||
7079 | reflect-metadata@^0.1.12: | 5952 | reflect-metadata@^0.1.12: |
7080 | version "0.1.13" | 5953 | version "0.1.13" |
7081 | resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" | 5954 | resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" |
7082 | integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== | 5955 | integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== |
7083 | 5956 | ||
7084 | regenerator-runtime@^0.12.0: | 5957 | regenerator-runtime@^0.13.2: |
7085 | version "0.12.1" | 5958 | version "0.13.2" |
7086 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" | 5959 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" |
7087 | integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== | 5960 | integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA== |
7088 | 5961 | ||
7089 | regex-not@^1.0.0, regex-not@^1.0.2: | 5962 | regex-not@^1.0.0, regex-not@^1.0.2: |
7090 | version "1.0.2" | 5963 | version "1.0.2" |
@@ -7135,7 +6008,7 @@ repeat-string@^1.6.1: | |||
7135 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" | 6008 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" |
7136 | integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= | 6009 | integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= |
7137 | 6010 | ||
7138 | request@^2.81.0, request@^2.83.0, request@^2.87.0, request@^2.88.0, request@~2.88.0: | 6011 | request@^2.81.0, request@^2.83.0, request@~2.88.0: |
7139 | version "2.88.0" | 6012 | version "2.88.0" |
7140 | resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" | 6013 | resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" |
7141 | integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== | 6014 | integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== |
@@ -7171,6 +6044,11 @@ require-main-filename@^1.0.1: | |||
7171 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" | 6044 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" |
7172 | integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= | 6045 | integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= |
7173 | 6046 | ||
6047 | require-main-filename@^2.0.0: | ||
6048 | version "2.0.0" | ||
6049 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" | ||
6050 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== | ||
6051 | |||
7174 | require-uncached@^1.0.2: | 6052 | require-uncached@^1.0.2: |
7175 | version "1.0.3" | 6053 | version "1.0.3" |
7176 | resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" | 6054 | resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" |
@@ -7179,14 +6057,6 @@ require-uncached@^1.0.2: | |||
7179 | caller-path "^0.1.0" | 6057 | caller-path "^0.1.0" |
7180 | resolve-from "^1.0.0" | 6058 | resolve-from "^1.0.0" |
7181 | 6059 | ||
7182 | resolve-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 | |||
7190 | resolve-from@^1.0.0: | 6060 | resolve-from@^1.0.0: |
7191 | version "1.0.1" | 6061 | version "1.0.1" |
7192 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" | 6062 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" |
@@ -7202,11 +6072,6 @@ resolve-from@^3.0.0: | |||
7202 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" | 6072 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" |
7203 | integrity sha1-six699nWiBvItuZTM17rywoYh0g= | 6073 | integrity sha1-six699nWiBvItuZTM17rywoYh0g= |
7204 | 6074 | ||
7205 | resolve-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 | |||
7210 | resolve-pkg@^1.0.0: | 6075 | resolve-pkg@^1.0.0: |
7211 | version "1.0.0" | 6076 | version "1.0.0" |
7212 | resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-1.0.0.tgz#e19a15e78aca2e124461dc92b2e3943ef93494d9" | 6077 | resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-1.0.0.tgz#e19a15e78aca2e124461dc92b2e3943ef93494d9" |
@@ -7220,9 +6085,9 @@ resolve-url@^0.2.1: | |||
7220 | integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= | 6085 | integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= |
7221 | 6086 | ||
7222 | resolve@^1.10.0, resolve@^1.3.2: | 6087 | resolve@^1.10.0, resolve@^1.3.2: |
7223 | version "1.10.0" | 6088 | version "1.11.1" |
7224 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" | 6089 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" |
7225 | integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== | 6090 | integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== |
7226 | dependencies: | 6091 | dependencies: |
7227 | path-parse "^1.0.6" | 6092 | path-parse "^1.0.6" |
7228 | 6093 | ||
@@ -7254,22 +6119,12 @@ retry-as-promised@^3.1.0: | |||
7254 | dependencies: | 6119 | dependencies: |
7255 | any-promise "^1.3.0" | 6120 | any-promise "^1.3.0" |
7256 | 6121 | ||
7257 | retry@^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 | |||
7262 | retry@^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 | |||
7267 | revalidator@0.1.x: | 6122 | revalidator@0.1.x: |
7268 | version "0.1.8" | 6123 | version "0.1.8" |
7269 | resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" | 6124 | resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" |
7270 | integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs= | 6125 | integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs= |
7271 | 6126 | ||
7272 | rimraf@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: | 6127 | rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.4.2, rimraf@^2.6.1, rimraf@~2.6.2: |
7273 | version "2.6.3" | 6128 | version "2.6.3" |
7274 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" | 6129 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" |
7275 | integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== | 6130 | integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== |
@@ -7298,13 +6153,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" | 6153 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" |
7299 | integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== | 6154 | integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== |
7300 | 6155 | ||
7301 | run-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 | |||
7308 | run-series@^1.0.2: | 6156 | run-series@^1.0.2: |
7309 | version "1.1.8" | 6157 | version "1.1.8" |
7310 | resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36" | 6158 | resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36" |
@@ -7321,9 +6169,9 @@ rx-lite@^3.1.2: | |||
7321 | integrity sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI= | 6169 | integrity sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI= |
7322 | 6170 | ||
7323 | rxjs@^6.3.3: | 6171 | rxjs@^6.3.3: |
7324 | version "6.4.0" | 6172 | version "6.5.2" |
7325 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" | 6173 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7" |
7326 | integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw== | 6174 | integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg== |
7327 | dependencies: | 6175 | dependencies: |
7328 | tslib "^1.9.0" | 6176 | tslib "^1.9.0" |
7329 | 6177 | ||
@@ -7345,9 +6193,9 @@ safe-regex@^1.1.0: | |||
7345 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== | 6193 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== |
7346 | 6194 | ||
7347 | sass-lint@^1.12.1: | 6195 | sass-lint@^1.12.1: |
7348 | version "1.12.1" | 6196 | version "1.13.1" |
7349 | resolved "https://registry.yarnpkg.com/sass-lint/-/sass-lint-1.12.1.tgz#630f69c216aa206b8232fb2aa907bdf3336b6d83" | 6197 | resolved "https://registry.yarnpkg.com/sass-lint/-/sass-lint-1.13.1.tgz#5fd2b2792e9215272335eb0f0dc607f61e8acc8f" |
7350 | integrity sha1-Yw9pwhaqIGuCMvsqqQe98zNrbYM= | 6198 | integrity sha512-DSyah8/MyjzW2BWYmQWekYEKir44BpLqrCFsgs9iaWiVTcwZfwXHF586hh3D1n+/9ihUNMfd8iHAyb9KkGgs7Q== |
7351 | dependencies: | 6199 | dependencies: |
7352 | commander "^2.8.1" | 6200 | commander "^2.8.1" |
7353 | eslint "^2.7.0" | 6201 | eslint "^2.7.0" |
@@ -7391,7 +6239,7 @@ semver-diff@^2.0.0: | |||
7391 | dependencies: | 6239 | dependencies: |
7392 | semver "^5.0.3" | 6240 | semver "^5.0.3" |
7393 | 6241 | ||
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: | 6242 | "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" | 6243 | version "5.7.0" |
7396 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" | 6244 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" |
7397 | integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== | 6245 | integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== |
@@ -7401,10 +6249,10 @@ semver@4.3.2: | |||
7401 | resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" | 6249 | resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" |
7402 | integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c= | 6250 | integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c= |
7403 | 6251 | ||
7404 | semver@~5.3.0: | 6252 | semver@^6.0.0, semver@^6.1.1: |
7405 | version "5.3.0" | 6253 | version "6.1.1" |
7406 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" | 6254 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.1.1.tgz#53f53da9b30b2103cd4f15eab3a18ecbcb210c9b" |
7407 | integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= | 6255 | integrity sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ== |
7408 | 6256 | ||
7409 | send@0.13.1: | 6257 | send@0.13.1: |
7410 | version "0.13.1" | 6258 | version "0.13.1" |
@@ -7442,10 +6290,10 @@ send@0.13.2: | |||
7442 | range-parser "~1.0.3" | 6290 | range-parser "~1.0.3" |
7443 | statuses "~1.2.1" | 6291 | statuses "~1.2.1" |
7444 | 6292 | ||
7445 | send@0.16.2: | 6293 | send@0.17.1: |
7446 | version "0.16.2" | 6294 | version "0.17.1" |
7447 | resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" | 6295 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" |
7448 | integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== | 6296 | integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== |
7449 | dependencies: | 6297 | dependencies: |
7450 | debug "2.6.9" | 6298 | debug "2.6.9" |
7451 | depd "~1.1.2" | 6299 | depd "~1.1.2" |
@@ -7454,12 +6302,12 @@ send@0.16.2: | |||
7454 | escape-html "~1.0.3" | 6302 | escape-html "~1.0.3" |
7455 | etag "~1.8.1" | 6303 | etag "~1.8.1" |
7456 | fresh "0.5.2" | 6304 | fresh "0.5.2" |
7457 | http-errors "~1.6.2" | 6305 | http-errors "~1.7.2" |
7458 | mime "1.4.1" | 6306 | mime "1.6.0" |
7459 | ms "2.0.0" | 6307 | ms "2.1.1" |
7460 | on-finished "~2.3.0" | 6308 | on-finished "~2.3.0" |
7461 | range-parser "~1.2.0" | 6309 | range-parser "~1.2.1" |
7462 | statuses "~1.4.0" | 6310 | statuses "~1.5.0" |
7463 | 6311 | ||
7464 | sequelize-pool@^1.0.2: | 6312 | sequelize-pool@^1.0.2: |
7465 | version "1.0.2" | 6313 | version "1.0.2" |
@@ -7475,10 +6323,10 @@ sequelize-typescript@1.0.0-beta.2: | |||
7475 | dependencies: | 6323 | dependencies: |
7476 | glob "7.1.2" | 6324 | glob "7.1.2" |
7477 | 6325 | ||
7478 | sequelize@5.7.4: | 6326 | sequelize@5.8.7: |
7479 | version "5.7.4" | 6327 | version "5.8.7" |
7480 | resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-5.7.4.tgz#1631faadff65f3a345b9757fca60429c65ba8e57" | 6328 | resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-5.8.7.tgz#3af2fd6051277d5fb5b32054c7f8aac4c4a04107" |
7481 | integrity sha512-CaVYpAgZQEsGDuZ+Oq6uIZy4pxQxscotuh5UGIaFRa0VkTIgV0IiF7vAhSv+1Wn+NvhKCvgJJ85M34BP3AdGNg== | 6329 | integrity sha512-1rubZM8fAyCt5ipyS+3HJ3Jbmb8WesLdPJ3jIbTD+78EbuPZILFEA5fK0mliVRBx7oM7oPULeVX0lxSRXBV1jw== |
7482 | dependencies: | 6330 | dependencies: |
7483 | bluebird "^3.5.0" | 6331 | bluebird "^3.5.0" |
7484 | cls-bluebird "^2.1.0" | 6332 | cls-bluebird "^2.1.0" |
@@ -7496,15 +6344,15 @@ sequelize@5.7.4: | |||
7496 | validator "^10.11.0" | 6344 | validator "^10.11.0" |
7497 | wkx "^0.4.6" | 6345 | wkx "^0.4.6" |
7498 | 6346 | ||
7499 | serve-static@1.13.2: | 6347 | serve-static@1.14.1: |
7500 | version "1.13.2" | 6348 | version "1.14.1" |
7501 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" | 6349 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" |
7502 | integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== | 6350 | integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== |
7503 | dependencies: | 6351 | dependencies: |
7504 | encodeurl "~1.0.2" | 6352 | encodeurl "~1.0.2" |
7505 | escape-html "~1.0.3" | 6353 | escape-html "~1.0.3" |
7506 | parseurl "~1.3.2" | 6354 | parseurl "~1.3.3" |
7507 | send "0.16.2" | 6355 | send "0.17.1" |
7508 | 6356 | ||
7509 | serve-static@~1.10.2: | 6357 | serve-static@~1.10.2: |
7510 | version "1.10.3" | 6358 | version "1.10.3" |
@@ -7540,32 +6388,23 @@ set-value@^2.0.0: | |||
7540 | is-plain-object "^2.0.3" | 6388 | is-plain-object "^2.0.3" |
7541 | split-string "^3.0.1" | 6389 | split-string "^3.0.1" |
7542 | 6390 | ||
7543 | setprototypeof@1.1.0: | 6391 | setprototypeof@1.1.1: |
7544 | version "1.1.0" | 6392 | version "1.1.1" |
7545 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" | 6393 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" |
7546 | integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== | 6394 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== |
7547 | |||
7548 | sha@~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 | 6395 | ||
7556 | sharp@^0.22.0: | 6396 | sharp@^0.22.0: |
7557 | version "0.22.0" | 6397 | version "0.22.1" |
7558 | resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.22.0.tgz#cf4cfcb019941fd06ac24555d9f5bc84536d29be" | 6398 | resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.22.1.tgz#a67c0e75567f03dd5a7861b901fec04072c5b0f4" |
7559 | integrity sha512-yInpiWYvVbE0hJylso2Q2A7QaYFBxGdSlVVHGeUf1F9JsQNAUpmaqdnX54TImgKbSCy9mQpEAoGm1pcKCZhCsQ== | 6399 | integrity sha512-lXzSk/FL5b/MpWrT1pQZneKe25stVjEbl6uhhJcTULm7PhmJgKKRbTDM/vtjyUuC/RLqL2PRyC4rpKwbv3soEw== |
7560 | dependencies: | 6400 | dependencies: |
7561 | bindings "^1.5.0" | 6401 | color "^3.1.1" |
7562 | color "^3.1.0" | ||
7563 | detect-libc "^1.0.3" | 6402 | detect-libc "^1.0.3" |
7564 | fs-copy-file-sync "^1.1.1" | 6403 | fs-copy-file-sync "^1.1.1" |
7565 | nan "^2.13.1" | 6404 | nan "^2.13.2" |
7566 | npmlog "^4.1.2" | 6405 | npmlog "^4.1.2" |
7567 | prebuild-install "^5.2.5" | 6406 | prebuild-install "^5.3.0" |
7568 | semver "^5.6.0" | 6407 | semver "^6.0.0" |
7569 | simple-get "^3.0.3" | 6408 | simple-get "^3.0.3" |
7570 | tar "^4.4.8" | 6409 | tar "^4.4.8" |
7571 | tunnel-agent "^0.6.0" | 6410 | tunnel-agent "^0.6.0" |
@@ -7621,9 +6460,9 @@ simple-get@^3.0.0, simple-get@^3.0.1, simple-get@^3.0.3: | |||
7621 | simple-concat "^1.0.0" | 6460 | simple-concat "^1.0.0" |
7622 | 6461 | ||
7623 | simple-git@^1.85.0: | 6462 | simple-git@^1.85.0: |
7624 | version "1.110.0" | 6463 | version "1.113.0" |
7625 | resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.110.0.tgz#54eb179089d055a7783d32399246cebc9d9933e9" | 6464 | resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.113.0.tgz#668989728a1e9cf4ec6c72b69ea2eecc93489bea" |
7626 | integrity sha512-UYY0rQkknk0P5eb+KW+03F4TevZ9ou0H+LoGaj7iiVgpnZH4wdj/HTViy/1tNNkmIPcmtxuBqXWiYt2YwlRKOQ== | 6465 | integrity sha512-i9WVsrK2u0G/cASI9nh7voxOk9mhanWY9eGtWBDSYql6m49Yk5/Fan6uZsDr/xmzv8n+eQ8ahKCoEr8cvU3h+g== |
7627 | dependencies: | 6466 | dependencies: |
7628 | debug "^4.0.1" | 6467 | debug "^4.0.1" |
7629 | 6468 | ||
@@ -7664,39 +6503,24 @@ simple-websocket@^7.0.1: | |||
7664 | ws "^6.0.0" | 6503 | ws "^6.0.0" |
7665 | 6504 | ||
7666 | sitemap@^2.1.0: | 6505 | sitemap@^2.1.0: |
7667 | version "2.1.0" | 6506 | version "2.2.0" |
7668 | resolved "https://registry.yarnpkg.com/sitemap/-/sitemap-2.1.0.tgz#1633cb88c196d755ad94becfb1c1bcacc6d3425a" | 6507 | resolved "https://registry.yarnpkg.com/sitemap/-/sitemap-2.2.0.tgz#98b8502762c5d7e8c77c9be5061dce85b326f1b0" |
7669 | integrity sha512-AkfA7RDVCITQo+j5CpXsMJlZ/8ENO2NtgMHYIh+YMvex2Hao/oe3MQgNa03p0aWY6srCfUA1Q02OgiWCAiuccA== | 6508 | integrity sha512-9Zoi3UBhSIt5jWENDRUbzsqLMJ+Fha3P2aQ2PRghmh0FOivtHsC4FAJdkAEKHvATajd74BWp/57Yh7kz/UA53Q== |
7670 | dependencies: | 6509 | dependencies: |
7671 | lodash "^4.17.10" | 6510 | lodash "^4.17.10" |
7672 | url-join "^4.0.0" | 6511 | url-join "^4.0.0" |
7673 | xmlbuilder "^10.0.0" | 6512 | xmlbuilder "^10.0.0" |
7674 | 6513 | ||
7675 | slash@^1.0.0: | 6514 | slash@^3.0.0: |
7676 | version "1.0.0" | 6515 | version "3.0.0" |
7677 | resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" | 6516 | resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" |
7678 | integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= | 6517 | integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== |
7679 | |||
7680 | slash@^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 | 6518 | ||
7685 | slice-ansi@0.0.4: | 6519 | slice-ansi@0.0.4: |
7686 | version "0.0.4" | 6520 | version "0.0.4" |
7687 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" | 6521 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" |
7688 | integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU= | 6522 | integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU= |
7689 | 6523 | ||
7690 | slide@^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 | |||
7695 | smart-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 | |||
7700 | smtp-connection@2.3.1: | 6524 | smtp-connection@2.3.1: |
7701 | version "2.3.1" | 6525 | version "2.3.1" |
7702 | resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-2.3.1.tgz#d169c8f1c9a73854134cdabe6fb818237dfc4fba" | 6526 | resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-2.3.1.tgz#d169c8f1c9a73854134cdabe6fb818237dfc4fba" |
@@ -7836,35 +6660,6 @@ socket.io@^2.2.0: | |||
7836 | socket.io-client "2.2.0" | 6660 | socket.io-client "2.2.0" |
7837 | socket.io-parser "~3.3.0" | 6661 | socket.io-parser "~3.3.0" |
7838 | 6662 | ||
7839 | socks-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 | |||
7847 | socks@~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 | |||
7855 | sorted-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 | |||
7860 | sorted-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 | |||
7868 | source-map-resolve@^0.5.0: | 6663 | source-map-resolve@^0.5.0: |
7869 | version "0.5.2" | 6664 | version "0.5.2" |
7870 | resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" | 6665 | resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" |
@@ -7877,9 +6672,9 @@ source-map-resolve@^0.5.0: | |||
7877 | urix "^0.1.0" | 6672 | urix "^0.1.0" |
7878 | 6673 | ||
7879 | source-map-support@^0.5.0, source-map-support@^0.5.6: | 6674 | source-map-support@^0.5.0, source-map-support@^0.5.6: |
7880 | version "0.5.11" | 6675 | version "0.5.12" |
7881 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.11.tgz#efac2ce0800355d026326a0ca23e162aeac9a4e2" | 6676 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" |
7882 | integrity sha512-//sajEx/fGL3iw6fltKMdPvy8kL3kJ2O3iuYlRoT3k9Kb4BjOoZ+BZzaNHeuaruSt+Kf3Zk9tnfAQg9/AJqUVQ== | 6677 | integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== |
7883 | dependencies: | 6678 | dependencies: |
7884 | buffer-from "^1.0.0" | 6679 | buffer-from "^1.0.0" |
7885 | source-map "^0.6.0" | 6680 | source-map "^0.6.0" |
@@ -7926,20 +6721,15 @@ spdx-expression-parse@^3.0.0: | |||
7926 | spdx-license-ids "^3.0.0" | 6721 | spdx-license-ids "^3.0.0" |
7927 | 6722 | ||
7928 | spdx-license-ids@^3.0.0: | 6723 | spdx-license-ids@^3.0.0: |
7929 | version "3.0.3" | 6724 | version "3.0.4" |
7930 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e" | 6725 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" |
7931 | integrity sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g== | 6726 | integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA== |
7932 | 6727 | ||
7933 | speedometer@^1.0.0: | 6728 | speedometer@^1.0.0: |
7934 | version "1.1.0" | 6729 | version "1.1.0" |
7935 | resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.1.0.tgz#a30b13abda45687a1a76977012c060f2ac8a7934" | 6730 | resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.1.0.tgz#a30b13abda45687a1a76977012c060f2ac8a7934" |
7936 | integrity sha512-z/wAiTESw2XVPssY2XRcme4niTc4S5FkkJ4gknudtVoc33Zil8TdTxHy5torRcgqMqksJV2Yz8HQcvtbsnw0mQ== | 6731 | integrity sha512-z/wAiTESw2XVPssY2XRcme4niTc4S5FkkJ4gknudtVoc33Zil8TdTxHy5torRcgqMqksJV2Yz8HQcvtbsnw0mQ== |
7937 | 6732 | ||
7938 | split-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 | |||
7943 | split-string@^3.0.1, split-string@^3.0.2: | 6733 | split-string@^3.0.1, split-string@^3.0.2: |
7944 | version "3.1.0" | 6734 | version "3.1.0" |
7945 | resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" | 6735 | resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" |
@@ -7993,13 +6783,6 @@ sshpk@^1.7.0: | |||
7993 | safer-buffer "^2.0.2" | 6783 | safer-buffer "^2.0.2" |
7994 | tweetnacl "~0.14.0" | 6784 | tweetnacl "~0.14.0" |
7995 | 6785 | ||
7996 | ssri@^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 | |||
8003 | stack-trace@0.0.x: | 6786 | stack-trace@0.0.x: |
8004 | version "0.0.10" | 6787 | version "0.0.10" |
8005 | resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" | 6788 | resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" |
@@ -8023,7 +6806,7 @@ static-extend@^0.1.1: | |||
8023 | define-property "^0.2.5" | 6806 | define-property "^0.2.5" |
8024 | object-copy "^0.1.0" | 6807 | object-copy "^0.1.0" |
8025 | 6808 | ||
8026 | statuses@1, "statuses@>= 1.4.0 < 2": | 6809 | statuses@1, "statuses@>= 1.5.0 < 2", statuses@~1.5.0: |
8027 | version "1.5.0" | 6810 | version "1.5.0" |
8028 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" | 6811 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" |
8029 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= | 6812 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= |
@@ -8038,27 +6821,6 @@ statuses@~1.2.1: | |||
8038 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.2.1.tgz#dded45cc18256d51ed40aec142489d5c61026d28" | 6821 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.2.1.tgz#dded45cc18256d51ed40aec142489d5c61026d28" |
8039 | integrity sha1-3e1FzBglbVHtQK7BQkidXGECbSg= | 6822 | integrity sha1-3e1FzBglbVHtQK7BQkidXGECbSg= |
8040 | 6823 | ||
8041 | statuses@~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 | |||
8046 | stream-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 | |||
8054 | stream-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 | |||
8062 | stream-shift@^1.0.0: | 6824 | stream-shift@^1.0.0: |
8063 | version "1.0.0" | 6825 | version "1.0.0" |
8064 | resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" | 6826 | resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" |
@@ -8109,11 +6871,6 @@ streamsearch@0.1.2: | |||
8109 | resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" | 6871 | resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" |
8110 | integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= | 6872 | integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= |
8111 | 6873 | ||
8112 | strict-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 | |||
8117 | string-argv@^0.0.2: | 6874 | string-argv@^0.0.2: |
8118 | version "0.0.2" | 6875 | version "0.0.2" |
8119 | resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.0.2.tgz#dac30408690c21f3c3630a3ff3a05877bdcbd736" | 6876 | resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.0.2.tgz#dac30408690c21f3c3630a3ff3a05877bdcbd736" |
@@ -8136,6 +6893,15 @@ string-width@^1.0.1: | |||
8136 | is-fullwidth-code-point "^2.0.0" | 6893 | is-fullwidth-code-point "^2.0.0" |
8137 | strip-ansi "^4.0.0" | 6894 | strip-ansi "^4.0.0" |
8138 | 6895 | ||
6896 | string-width@^3.0.0, string-width@^3.1.0: | ||
6897 | version "3.1.0" | ||
6898 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" | ||
6899 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== | ||
6900 | dependencies: | ||
6901 | emoji-regex "^7.0.1" | ||
6902 | is-fullwidth-code-point "^2.0.0" | ||
6903 | strip-ansi "^5.1.0" | ||
6904 | |||
8139 | string2compact@^1.1.1, string2compact@^1.2.5: | 6905 | string2compact@^1.1.1, string2compact@^1.2.5: |
8140 | version "1.3.0" | 6906 | version "1.3.0" |
8141 | resolved "https://registry.yarnpkg.com/string2compact/-/string2compact-1.3.0.tgz#22d946127b082d1203c51316af60117a337423c3" | 6907 | resolved "https://registry.yarnpkg.com/string2compact/-/string2compact-1.3.0.tgz#22d946127b082d1203c51316af60117a337423c3" |
@@ -8172,11 +6938,6 @@ stringify-object@^3.2.2: | |||
8172 | is-obj "^1.0.1" | 6938 | is-obj "^1.0.1" |
8173 | is-regexp "^1.0.0" | 6939 | is-regexp "^1.0.0" |
8174 | 6940 | ||
8175 | stringify-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 | |||
8180 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: | 6941 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: |
8181 | version "3.0.1" | 6942 | version "3.0.1" |
8182 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" | 6943 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" |
@@ -8191,6 +6952,13 @@ strip-ansi@^4.0.0: | |||
8191 | dependencies: | 6952 | dependencies: |
8192 | ansi-regex "^3.0.0" | 6953 | ansi-regex "^3.0.0" |
8193 | 6954 | ||
6955 | strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: | ||
6956 | version "5.2.0" | ||
6957 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" | ||
6958 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== | ||
6959 | dependencies: | ||
6960 | ansi-regex "^4.1.0" | ||
6961 | |||
8194 | strip-eof@^1.0.0: | 6962 | strip-eof@^1.0.0: |
8195 | version "1.0.0" | 6963 | version "1.0.0" |
8196 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" | 6964 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" |
@@ -8206,15 +6974,6 @@ strip-json-comments@~1.0.1: | |||
8206 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" | 6974 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" |
8207 | integrity sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E= | 6975 | integrity sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E= |
8208 | 6976 | ||
8209 | summon-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 | |||
8218 | superagent@^3.8.3: | 6977 | superagent@^3.8.3: |
8219 | version "3.8.3" | 6978 | version "3.8.3" |
8220 | resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" | 6979 | resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" |
@@ -8304,10 +7063,10 @@ symbol-observable@^1.1.0: | |||
8304 | resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" | 7063 | resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" |
8305 | integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== | 7064 | integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== |
8306 | 7065 | ||
8307 | synchronous-promise@^2.0.5: | 7066 | synchronous-promise@^2.0.6: |
8308 | version "2.0.7" | 7067 | version "2.0.9" |
8309 | resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.7.tgz#3574b3d2fae86b145356a4b89103e1577f646fe3" | 7068 | resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.9.tgz#b83db98e9e7ae826bf9c8261fd8ac859126c780a" |
8310 | integrity sha512-16GbgwTmFMYFyQMLvtQjvNWh30dsFe1cAW5Fg1wm5+dg84L9Pe36mftsIRU95/W2YsISxsz/xq4VB23sqpgb/A== | 7069 | integrity sha512-LO95GIW16x69LuND1nuuwM4pjgFGupg7pZ/4lU86AmchPKrhk0o2tpMU2unXRrqo81iAFe1YJ0nAGEVwsrZAgg== |
8311 | 7070 | ||
8312 | table@^3.7.8: | 7071 | table@^3.7.8: |
8313 | version "3.8.3" | 7072 | version "3.8.3" |
@@ -8344,27 +7103,18 @@ tar-stream@^1.1.2: | |||
8344 | to-buffer "^1.1.1" | 7103 | to-buffer "^1.1.1" |
8345 | xtend "^4.0.0" | 7104 | xtend "^4.0.0" |
8346 | 7105 | ||
8347 | tar@^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 | |||
8356 | tar@^4, tar@^4.4.8: | 7106 | tar@^4, tar@^4.4.8: |
8357 | version "4.4.8" | 7107 | version "4.4.10" |
8358 | resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" | 7108 | resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" |
8359 | integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== | 7109 | integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== |
8360 | dependencies: | 7110 | dependencies: |
8361 | chownr "^1.1.1" | 7111 | chownr "^1.1.1" |
8362 | fs-minipass "^1.2.5" | 7112 | fs-minipass "^1.2.5" |
8363 | minipass "^2.3.4" | 7113 | minipass "^2.3.5" |
8364 | minizlib "^1.1.1" | 7114 | minizlib "^1.2.1" |
8365 | mkdirp "^0.5.0" | 7115 | mkdirp "^0.5.0" |
8366 | safe-buffer "^5.1.2" | 7116 | safe-buffer "^5.1.2" |
8367 | yallist "^3.0.2" | 7117 | yallist "^3.0.3" |
8368 | 7118 | ||
8369 | term-size@^1.2.0: | 7119 | term-size@^1.2.0: |
8370 | version "1.2.0" | 7120 | version "1.2.0" |
@@ -8404,7 +7154,7 @@ through2@^1.0.0: | |||
8404 | readable-stream ">=1.1.13-1 <1.2.0-0" | 7154 | readable-stream ">=1.1.13-1 <1.2.0-0" |
8405 | xtend ">=4.0.0 <4.1.0-0" | 7155 | xtend ">=4.0.0 <4.1.0-0" |
8406 | 7156 | ||
8407 | through2@^2.0.0, through2@^2.0.3: | 7157 | through2@^2.0.3: |
8408 | version "2.0.5" | 7158 | version "2.0.5" |
8409 | resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" | 7159 | resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" |
8410 | integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== | 7160 | integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== |
@@ -8412,7 +7162,7 @@ through2@^2.0.0, through2@^2.0.3: | |||
8412 | readable-stream "~2.3.6" | 7162 | readable-stream "~2.3.6" |
8413 | xtend "~4.0.1" | 7163 | xtend "~4.0.1" |
8414 | 7164 | ||
8415 | through@2, "through@>=2.2.7 <3", through@^2.3.6: | 7165 | through@2, through@^2.3.6: |
8416 | version "2.3.8" | 7166 | version "2.3.8" |
8417 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" | 7167 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" |
8418 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= | 7168 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= |
@@ -8435,11 +7185,6 @@ timers-ext@^0.1.5: | |||
8435 | es5-ext "~0.10.46" | 7185 | es5-ext "~0.10.46" |
8436 | next-tick "1" | 7186 | next-tick "1" |
8437 | 7187 | ||
8438 | tiny-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 | |||
8443 | tmp@0.0.x: | 7188 | tmp@0.0.x: |
8444 | version "0.0.33" | 7189 | version "0.0.33" |
8445 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" | 7190 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" |
@@ -8498,6 +7243,11 @@ to-utf-8@^1.2.0: | |||
8498 | peek-stream "^1.1.1" | 7243 | peek-stream "^1.1.1" |
8499 | stream-splicer "^1.3.1" | 7244 | stream-splicer "^1.3.1" |
8500 | 7245 | ||
7246 | toidentifier@1.0.0: | ||
7247 | version "1.0.0" | ||
7248 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" | ||
7249 | integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== | ||
7250 | |||
8501 | toposort-class@^1.0.1: | 7251 | toposort-class@^1.0.1: |
8502 | version "1.0.1" | 7252 | version "1.0.1" |
8503 | resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988" | 7253 | resolved "https://registry.yarnpkg.com/toposort-class/-/toposort-class-1.0.1.tgz#7ffd1f78c8be28c3ba45cd4e1a3f5ee193bd9988" |
@@ -8553,13 +7303,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" | 7303 | resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" |
8554 | integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== | 7304 | integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== |
8555 | 7305 | ||
8556 | ts-node@8.0.3: | 7306 | ts-node@8.2.0: |
8557 | version "8.0.3" | 7307 | version "8.2.0" |
8558 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.0.3.tgz#aa60b836a24dafd8bf21b54766841a232fdbc641" | 7308 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.2.0.tgz#4a89754b00560bb24cd54526e1685fa38c45f240" |
8559 | integrity sha512-2qayBA4vdtVRuDo11DEFSsD/SFsBXQBRZZhbRGSIkmYmVkWjULn/GGMdG10KVqkaGndljfaTD8dKjWgcejO8YA== | 7309 | integrity sha512-m8XQwUurkbYqXrKqr3WHCW310utRNvV5OnRVeISeea7LoCWVcdfeB/Ntl8JYWFh+WRoUAdBgESrzKochQt7sMw== |
8560 | dependencies: | 7310 | dependencies: |
8561 | arg "^4.1.0" | 7311 | arg "^4.1.0" |
8562 | diff "^3.1.0" | 7312 | diff "^4.0.1" |
8563 | make-error "^1.1.1" | 7313 | make-error "^1.1.1" |
8564 | source-map-support "^0.5.6" | 7314 | source-map-support "^0.5.6" |
8565 | yn "^3.0.0" | 7315 | yn "^3.0.0" |
@@ -8591,17 +7341,17 @@ tslint-eslint-rules@^5.3.1: | |||
8591 | tsutils "^3.0.0" | 7341 | tsutils "^3.0.0" |
8592 | 7342 | ||
8593 | tslint@^5.7.0: | 7343 | tslint@^5.7.0: |
8594 | version "5.15.0" | 7344 | version "5.17.0" |
8595 | resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.15.0.tgz#6ffb180986d63afa1e531feb2a134dbf961e27d3" | 7345 | resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.17.0.tgz#f9f0ce2011d8e90debaa6e9b4975f24cd16852b8" |
8596 | integrity sha512-6bIEujKR21/3nyeoX2uBnE8s+tMXCQXhqMmaIPJpHmXJoBJPTLcI7/VHRtUwMhnLVdwLqqY3zmd8Dxqa5CVdJA== | 7346 | integrity sha512-pflx87WfVoYepTet3xLfDOLDm9Jqi61UXIKePOuca0qoAZyrGWonDG9VTbji58Fy+8gciUn8Bt7y69+KEVjc/w== |
8597 | dependencies: | 7347 | dependencies: |
8598 | babel-code-frame "^6.22.0" | 7348 | "@babel/code-frame" "^7.0.0" |
8599 | builtin-modules "^1.1.1" | 7349 | builtin-modules "^1.1.1" |
8600 | chalk "^2.3.0" | 7350 | chalk "^2.3.0" |
8601 | commander "^2.12.1" | 7351 | commander "^2.12.1" |
8602 | diff "^3.2.0" | 7352 | diff "^3.2.0" |
8603 | glob "^7.1.1" | 7353 | glob "^7.1.1" |
8604 | js-yaml "^3.13.0" | 7354 | js-yaml "^3.13.1" |
8605 | minimatch "^3.0.4" | 7355 | minimatch "^3.0.4" |
8606 | mkdirp "^0.5.1" | 7356 | mkdirp "^0.5.1" |
8607 | resolve "^1.3.2" | 7357 | resolve "^1.3.2" |
@@ -8617,9 +7367,9 @@ tsutils@^2.29.0: | |||
8617 | tslib "^1.8.1" | 7367 | tslib "^1.8.1" |
8618 | 7368 | ||
8619 | tsutils@^3.0.0: | 7369 | tsutils@^3.0.0: |
8620 | version "3.9.1" | 7370 | version "3.14.0" |
8621 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.9.1.tgz#2a40dc742943c71eca6d5c1994fcf999956be387" | 7371 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.14.0.tgz#bf8d5a7bae5369331fa0f2b0a5a10bd7f7396c77" |
8622 | integrity sha512-hrxVtLtPqQr//p8/msPT1X1UYXUjizqSit5d9AQ5k38TcV38NyecL5xODNxa73cLe/5sdiJ+w1FqzDhRBA/anA== | 7372 | integrity sha512-SmzGbB0l+8I0QwsPgjooFRaRvHLBLNYM8SeQ0k6rtNDru5sCGeLJcZdwilNndN+GysuFjF5EIYgN8GfFG6UeUw== |
8623 | dependencies: | 7373 | dependencies: |
8624 | tslib "^1.8.1" | 7374 | tslib "^1.8.1" |
8625 | 7375 | ||
@@ -8630,10 +7380,10 @@ tunnel-agent@^0.6.0: | |||
8630 | dependencies: | 7380 | dependencies: |
8631 | safe-buffer "^5.0.1" | 7381 | safe-buffer "^5.0.1" |
8632 | 7382 | ||
8633 | tv4@~1.2.7: | 7383 | tv4@^1.3.0: |
8634 | version "1.2.7" | 7384 | version "1.3.0" |
8635 | resolved "https://registry.yarnpkg.com/tv4/-/tv4-1.2.7.tgz#bd29389afc73ade49ae5f48142b5d544bf68d120" | 7385 | resolved "https://registry.yarnpkg.com/tv4/-/tv4-1.3.0.tgz#d020c846fadd50c855abb25ebaecc68fc10f7963" |
8636 | integrity sha1-vSk4mvxzreSa5fSBQrXVRL9o0SA= | 7386 | integrity sha1-0CDIRvrdUMhVq7JeuuzGj8EPeWM= |
8637 | 7387 | ||
8638 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: | 7388 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: |
8639 | version "0.14.5" | 7389 | version "0.14.5" |
@@ -8657,6 +7407,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" | 7407 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" |
8658 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== | 7408 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== |
8659 | 7409 | ||
7410 | type-fest@^0.3.0: | ||
7411 | version "0.3.1" | ||
7412 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" | ||
7413 | integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== | ||
7414 | |||
7415 | type-fest@^0.4.1: | ||
7416 | version "0.4.1" | ||
7417 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8" | ||
7418 | integrity sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw== | ||
7419 | |||
8660 | type-is@1.6.15: | 7420 | type-is@1.6.15: |
8661 | version "1.6.15" | 7421 | version "1.6.15" |
8662 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" | 7422 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" |
@@ -8665,13 +7425,13 @@ type-is@1.6.15: | |||
8665 | media-typer "0.3.0" | 7425 | media-typer "0.3.0" |
8666 | mime-types "~2.1.15" | 7426 | mime-types "~2.1.15" |
8667 | 7427 | ||
8668 | type-is@^1.6.4, type-is@~1.6.16, type-is@~1.6.6: | 7428 | type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18, type-is@~1.6.6: |
8669 | version "1.6.16" | 7429 | version "1.6.18" |
8670 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" | 7430 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" |
8671 | integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== | 7431 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== |
8672 | dependencies: | 7432 | dependencies: |
8673 | media-typer "0.3.0" | 7433 | media-typer "0.3.0" |
8674 | mime-types "~2.1.18" | 7434 | mime-types "~2.1.24" |
8675 | 7435 | ||
8676 | typedarray-to-buffer@^3.0.0: | 7436 | typedarray-to-buffer@^3.0.0: |
8677 | version "3.1.5" | 7437 | version "3.1.5" |
@@ -8686,14 +7446,9 @@ typedarray@^0.0.6: | |||
8686 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= | 7446 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= |
8687 | 7447 | ||
8688 | typescript@^3.4.3: | 7448 | typescript@^3.4.3: |
8689 | version "3.4.3" | 7449 | version "3.5.1" |
8690 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.3.tgz#0eb320e4ace9b10eadf5bc6103286b0f8b7c224f" | 7450 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.1.tgz#ba72a6a600b2158139c5dd8850f700e231464202" |
8691 | integrity sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ== | 7451 | integrity sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw== |
8692 | |||
8693 | uid-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 | 7452 | ||
8698 | uint64be@^2.0.2: | 7453 | uint64be@^2.0.2: |
8699 | version "2.0.2" | 7454 | version "2.0.2" |
@@ -8707,11 +7462,6 @@ ultron@1.0.x: | |||
8707 | resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" | 7462 | resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" |
8708 | integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po= | 7463 | integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po= |
8709 | 7464 | ||
8710 | umask@^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 | |||
8715 | undefsafe@^2.0.2: | 7465 | undefsafe@^2.0.2: |
8716 | version "2.0.2" | 7466 | version "2.0.2" |
8717 | resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76" | 7467 | resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76" |
@@ -8719,18 +7469,6 @@ undefsafe@^2.0.2: | |||
8719 | dependencies: | 7469 | dependencies: |
8720 | debug "^2.2.0" | 7470 | debug "^2.2.0" |
8721 | 7471 | ||
8722 | underscore-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 | |||
8729 | underscore@*: | ||
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 | |||
8734 | union-value@^1.0.0: | 7472 | union-value@^1.0.0: |
8735 | version "1.0.0" | 7473 | version "1.0.0" |
8736 | resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" | 7474 | resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" |
@@ -8746,20 +7484,6 @@ uniq@^1.0.1: | |||
8746 | resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" | 7484 | resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" |
8747 | integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= | 7485 | integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= |
8748 | 7486 | ||
8749 | unique-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 | |||
8756 | unique-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 | |||
8763 | unique-string@^1.0.0: | 7487 | unique-string@^1.0.0: |
8764 | version "1.0.0" | 7488 | version "1.0.0" |
8765 | resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" | 7489 | resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" |
@@ -8800,7 +7524,7 @@ upath@^1.1.1: | |||
8800 | resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" | 7524 | resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" |
8801 | integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== | 7525 | integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== |
8802 | 7526 | ||
8803 | update-notifier@^2.3.0, update-notifier@^2.5.0: | 7527 | update-notifier@^2.5.0: |
8804 | version "2.5.0" | 7528 | version "2.5.0" |
8805 | resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" | 7529 | resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" |
8806 | integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw== | 7530 | integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw== |
@@ -8892,11 +7616,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" | 7616 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" |
8893 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= | 7617 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= |
8894 | 7618 | ||
8895 | util-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 | |||
8900 | util.promisify@^1.0.0: | 7619 | util.promisify@^1.0.0: |
8901 | version "1.0.0" | 7620 | version "1.0.0" |
8902 | resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" | 7621 | resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" |
@@ -8947,7 +7666,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" | 7666 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" |
8948 | integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== | 7667 | integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== |
8949 | 7668 | ||
8950 | validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: | 7669 | validate-npm-package-license@^3.0.1: |
8951 | version "3.0.4" | 7670 | version "3.0.4" |
8952 | resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" | 7671 | 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== | 7672 | integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== |
@@ -8955,18 +7674,16 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: | |||
8955 | spdx-correct "^3.0.0" | 7674 | spdx-correct "^3.0.0" |
8956 | spdx-expression-parse "^3.0.0" | 7675 | spdx-expression-parse "^3.0.0" |
8957 | 7676 | ||
8958 | validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0: | 7677 | validator@^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 | |||
8965 | validator@^10.0.0, validator@^10.11.0, validator@^10.2.0, validator@^10.4.0: | ||
8966 | version "10.11.0" | 7678 | version "10.11.0" |
8967 | resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" | 7679 | resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" |
8968 | integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== | 7680 | integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== |
8969 | 7681 | ||
7682 | validator@^11.0.0: | ||
7683 | version "11.0.0" | ||
7684 | resolved "https://registry.yarnpkg.com/validator/-/validator-11.0.0.tgz#fb10128bfb1fd14ce4ed36b79fc94289eae70667" | ||
7685 | integrity sha512-+wnGLYqaKV2++nUv60uGzUJyJQwYVOin6pn1tgEiFCeCQO60yeu3Og9/yPccbBX574kxIcEJicogkzx6s6eyag== | ||
7686 | |||
8970 | vary@^1, vary@~1.1.2: | 7687 | vary@^1, vary@~1.1.2: |
8971 | version "1.1.2" | 7688 | version "1.1.2" |
8972 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" | 7689 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" |
@@ -9000,13 +7717,6 @@ videostream@^2.5.1: | |||
9000 | pump "^3.0.0" | 7717 | pump "^3.0.0" |
9001 | range-slice-stream "^2.0.0" | 7718 | range-slice-stream "^2.0.0" |
9002 | 7719 | ||
9003 | wcwidth@^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 | |||
9010 | webfinger.js@^2.6.6: | 7720 | webfinger.js@^2.6.6: |
9011 | version "2.7.0" | 7721 | version "2.7.0" |
9012 | resolved "https://registry.yarnpkg.com/webfinger.js/-/webfinger.js-2.7.0.tgz#403354a14a65aeeba64c1408c18a387487cea106" | 7722 | resolved "https://registry.yarnpkg.com/webfinger.js/-/webfinger.js-2.7.0.tgz#403354a14a65aeeba64c1408c18a387487cea106" |
@@ -9070,7 +7780,7 @@ which-pm-runs@^1.0.0: | |||
9070 | resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" | 7780 | resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" |
9071 | integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= | 7781 | integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= |
9072 | 7782 | ||
9073 | which@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: | 7783 | which@1.3.1, which@^1.1.1, which@^1.2.10, which@^1.2.9, which@^1.3.1: |
9074 | version "1.3.1" | 7784 | version "1.3.1" |
9075 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" | 7785 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" |
9076 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== | 7786 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== |
@@ -9144,13 +7854,6 @@ wordwrap@~1.0.0: | |||
9144 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" | 7854 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" |
9145 | integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= | 7855 | integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= |
9146 | 7856 | ||
9147 | worker-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 | |||
9154 | wrap-ansi@^2.0.0: | 7857 | wrap-ansi@^2.0.0: |
9155 | version "2.1.0" | 7858 | version "2.1.0" |
9156 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" | 7859 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" |
@@ -9167,15 +7870,24 @@ wrap-ansi@^3.0.1: | |||
9167 | string-width "^2.1.1" | 7870 | string-width "^2.1.1" |
9168 | strip-ansi "^4.0.0" | 7871 | strip-ansi "^4.0.0" |
9169 | 7872 | ||
7873 | wrap-ansi@^5.1.0: | ||
7874 | version "5.1.0" | ||
7875 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" | ||
7876 | integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== | ||
7877 | dependencies: | ||
7878 | ansi-styles "^3.2.0" | ||
7879 | string-width "^3.0.0" | ||
7880 | strip-ansi "^5.0.0" | ||
7881 | |||
9170 | wrappy@1: | 7882 | wrappy@1: |
9171 | version "1.0.2" | 7883 | version "1.0.2" |
9172 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" | 7884 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" |
9173 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= | 7885 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= |
9174 | 7886 | ||
9175 | write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: | 7887 | write-file-atomic@^2.0.0: |
9176 | version "2.4.2" | 7888 | version "2.4.3" |
9177 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.2.tgz#a7181706dfba17855d221140a9c06e15fcdd87b9" | 7889 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" |
9178 | integrity sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g== | 7890 | integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== |
9179 | dependencies: | 7891 | dependencies: |
9180 | graceful-fs "^4.1.11" | 7892 | graceful-fs "^4.1.11" |
9181 | imurmurhash "^0.1.4" | 7893 | imurmurhash "^0.1.4" |
@@ -9203,6 +7915,13 @@ ws@^6.0.0: | |||
9203 | dependencies: | 7915 | dependencies: |
9204 | async-limiter "~1.0.0" | 7916 | async-limiter "~1.0.0" |
9205 | 7917 | ||
7918 | ws@^7.0.0: | ||
7919 | version "7.0.0" | ||
7920 | resolved "https://registry.yarnpkg.com/ws/-/ws-7.0.0.tgz#79351cbc3f784b3c20d0821baf4b4ff809ffbf51" | ||
7921 | integrity sha512-cknCal4k0EAOrh1SHHPPWWh4qm93g1IuGGGwBjWkXmCG7LsDtL8w9w+YVfaF+KSVwiHQKDIMsSLBVftKf9d1pg== | ||
7922 | dependencies: | ||
7923 | async-limiter "^1.0.0" | ||
7924 | |||
9206 | ws@~6.1.0: | 7925 | ws@~6.1.0: |
9207 | version "6.1.4" | 7926 | version "6.1.4" |
9208 | resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" | 7927 | resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" |
@@ -9231,9 +7950,9 @@ xhr2@^0.1.4: | |||
9231 | integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= | 7950 | integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= |
9232 | 7951 | ||
9233 | xliff@^4.0.0: | 7952 | xliff@^4.0.0: |
9234 | version "4.3.0" | 7953 | version "4.3.1" |
9235 | resolved "https://registry.yarnpkg.com/xliff/-/xliff-4.3.0.tgz#de08098a63ead8afde0bae83f059b8cbf3badaf1" | 7954 | resolved "https://registry.yarnpkg.com/xliff/-/xliff-4.3.1.tgz#ae82d1c6283014aa7506c9957bcb3f95ed1ce505" |
9236 | integrity sha512-YDGHMdgmzDOjDm9ys+CdesxC9NBaxOcARR8fdJKHS8qY+XbW6g0BAaRBj0ssC1H9s5lrY0m2uqLCu0HB58K2ag== | 7955 | integrity sha512-SERrOPuKZ/5XyEiv+cXgIjidQq4vp6HYS0yBS2GwC1TDJiREFaUIin3qg4OBlD6jdFWdPOMwkXGackAvgZ6+LQ== |
9237 | dependencies: | 7956 | dependencies: |
9238 | xml-js "1.6.11" | 7957 | xml-js "1.6.11" |
9239 | 7958 | ||
@@ -9287,11 +8006,6 @@ xmlhttprequest-ssl@~1.5.4: | |||
9287 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" | 8006 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" |
9288 | integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= | 8007 | integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= |
9289 | 8008 | ||
9290 | y18n@^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: | 8009 | "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: |
9296 | version "4.0.0" | 8010 | version "4.0.0" |
9297 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" | 8011 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" |
@@ -9302,12 +8016,20 @@ yallist@^2.1.2: | |||
9302 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" | 8016 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" |
9303 | integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= | 8017 | integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= |
9304 | 8018 | ||
9305 | yallist@^3.0.0, yallist@^3.0.2: | 8019 | yallist@^3.0.0, yallist@^3.0.3: |
9306 | version "3.0.3" | 8020 | version "3.0.3" |
9307 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" | 8021 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" |
9308 | integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== | 8022 | integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== |
9309 | 8023 | ||
9310 | yargs-parser@11.1.1, yargs-parser@^11.1.1: | 8024 | yargs-parser@13.0.0: |
8025 | version "13.0.0" | ||
8026 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b" | ||
8027 | integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw== | ||
8028 | dependencies: | ||
8029 | camelcase "^5.0.0" | ||
8030 | decamelize "^1.2.0" | ||
8031 | |||
8032 | yargs-parser@^11.1.1: | ||
9311 | version "11.1.1" | 8033 | version "11.1.1" |
9312 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" | 8034 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" |
9313 | integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== | 8035 | integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== |
@@ -9315,6 +8037,14 @@ yargs-parser@11.1.1, yargs-parser@^11.1.1: | |||
9315 | camelcase "^5.0.0" | 8037 | camelcase "^5.0.0" |
9316 | decamelize "^1.2.0" | 8038 | decamelize "^1.2.0" |
9317 | 8039 | ||
8040 | yargs-parser@^13.0.0, yargs-parser@^13.1.0: | ||
8041 | version "13.1.0" | ||
8042 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.0.tgz#7016b6dd03e28e1418a510e258be4bff5a31138f" | ||
8043 | integrity sha512-Yq+32PrijHRri0vVKQEm+ys8mbqWjLiwQkMFNXEENutzLPP0bE4Lcd4iA3OQY5HF+GD3xXxf0MEHb8E4/SA3AA== | ||
8044 | dependencies: | ||
8045 | camelcase "^5.0.0" | ||
8046 | decamelize "^1.2.0" | ||
8047 | |||
9318 | yargs-parser@^8.0.0: | 8048 | yargs-parser@^8.0.0: |
9319 | version "8.1.0" | 8049 | version "8.1.0" |
9320 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" | 8050 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" |
@@ -9322,13 +8052,6 @@ yargs-parser@^8.0.0: | |||
9322 | dependencies: | 8052 | dependencies: |
9323 | camelcase "^4.1.0" | 8053 | camelcase "^4.1.0" |
9324 | 8054 | ||
9325 | yargs-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 | |||
9332 | yargs-unparser@1.5.0: | 8055 | yargs-unparser@1.5.0: |
9333 | version "1.5.0" | 8056 | version "1.5.0" |
9334 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d" | 8057 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d" |
@@ -9338,7 +8061,24 @@ yargs-unparser@1.5.0: | |||
9338 | lodash "^4.17.11" | 8061 | lodash "^4.17.11" |
9339 | yargs "^12.0.5" | 8062 | yargs "^12.0.5" |
9340 | 8063 | ||
9341 | yargs@12.0.5, yargs@^12.0.1, yargs@^12.0.5: | 8064 | yargs@13.2.2: |
8065 | version "13.2.2" | ||
8066 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993" | ||
8067 | integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA== | ||
8068 | dependencies: | ||
8069 | cliui "^4.0.0" | ||
8070 | find-up "^3.0.0" | ||
8071 | get-caller-file "^2.0.1" | ||
8072 | os-locale "^3.1.0" | ||
8073 | require-directory "^2.1.1" | ||
8074 | require-main-filename "^2.0.0" | ||
8075 | set-blocking "^2.0.0" | ||
8076 | string-width "^3.0.0" | ||
8077 | which-module "^2.0.0" | ||
8078 | y18n "^4.0.0" | ||
8079 | yargs-parser "^13.0.0" | ||
8080 | |||
8081 | yargs@^12.0.1, yargs@^12.0.5: | ||
9342 | version "12.0.5" | 8082 | version "12.0.5" |
9343 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" | 8083 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" |
9344 | integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== | 8084 | integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== |
@@ -9356,23 +8096,22 @@ yargs@12.0.5, yargs@^12.0.1, yargs@^12.0.5: | |||
9356 | y18n "^3.2.1 || ^4.0.0" | 8096 | y18n "^3.2.1 || ^4.0.0" |
9357 | yargs-parser "^11.1.1" | 8097 | yargs-parser "^11.1.1" |
9358 | 8098 | ||
9359 | yargs@^11.0.0: | 8099 | yargs@^13.2.2: |
9360 | version "11.1.0" | 8100 | version "13.2.4" |
9361 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" | 8101 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" |
9362 | integrity sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A== | 8102 | integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg== |
9363 | dependencies: | 8103 | dependencies: |
9364 | cliui "^4.0.0" | 8104 | cliui "^5.0.0" |
9365 | decamelize "^1.1.1" | 8105 | find-up "^3.0.0" |
9366 | find-up "^2.1.0" | 8106 | get-caller-file "^2.0.1" |
9367 | get-caller-file "^1.0.1" | 8107 | os-locale "^3.1.0" |
9368 | os-locale "^2.0.0" | ||
9369 | require-directory "^2.1.1" | 8108 | require-directory "^2.1.1" |
9370 | require-main-filename "^1.0.1" | 8109 | require-main-filename "^2.0.0" |
9371 | set-blocking "^2.0.0" | 8110 | set-blocking "^2.0.0" |
9372 | string-width "^2.0.0" | 8111 | string-width "^3.0.0" |
9373 | which-module "^2.0.0" | 8112 | which-module "^2.0.0" |
9374 | y18n "^3.2.1" | 8113 | y18n "^4.0.0" |
9375 | yargs-parser "^9.0.2" | 8114 | yargs-parser "^13.1.0" |
9376 | 8115 | ||
9377 | yeast@0.1.2: | 8116 | yeast@0.1.2: |
9378 | version "0.1.2" | 8117 | version "0.1.2" |
@@ -9380,30 +8119,30 @@ yeast@0.1.2: | |||
9380 | integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= | 8119 | integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= |
9381 | 8120 | ||
9382 | yn@^3.0.0: | 8121 | yn@^3.0.0: |
9383 | version "3.0.0" | 8122 | version "3.1.0" |
9384 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.0.0.tgz#0073c6b56e92aed652fbdfd62431f2d6b9a7a091" | 8123 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.0.tgz#fcbe2db63610361afcc5eb9e0ac91e976d046114" |
9385 | integrity sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q== | 8124 | integrity sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg== |
9386 | 8125 | ||
9387 | youtube-dl@^1.12.2: | 8126 | youtube-dl@^2.0.0: |
9388 | version "1.13.1" | 8127 | version "2.0.0" |
9389 | resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-1.13.1.tgz#2da47c0dad3c5391e2172b7811da46501b82edc4" | 8128 | resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-2.0.0.tgz#64f85beff21a5b0b5651437ea51d10effd3dad5a" |
9390 | integrity sha512-89mUKwOavaojNKQlyzW+A7Dph5G/oPYs6T/PTMcvgdRQ5E2+uDQgYPxWHQDMBhHOkxQaxvxQTiTPKQLdg0OI4w== | 8129 | integrity sha512-1R5bcnBMVqQIk85wqTJ8pxPq5UbzxZXJy4KSaf3N1dedZG4uAzq5zuoiHcNcsGle5JtoHNpTWDBjTDhHO0SipQ== |
9391 | dependencies: | 8130 | dependencies: |
9392 | hh-mm-ss "~1.2.0" | 8131 | hh-mm-ss "~1.2.0" |
9393 | mkdirp "~0.5.1" | 8132 | mkdirp "~0.5.1" |
9394 | request "~2.88.0" | 8133 | request "~2.88.0" |
9395 | streamify "~0.2.9" | 8134 | streamify "~0.2.9" |
9396 | 8135 | ||
9397 | yup@^0.26.10: | 8136 | yup@^0.27.0: |
9398 | version "0.26.10" | 8137 | version "0.27.0" |
9399 | resolved "https://registry.yarnpkg.com/yup/-/yup-0.26.10.tgz#3545839663289038faf25facfc07e11fd67c0cb1" | 8138 | resolved "https://registry.yarnpkg.com/yup/-/yup-0.27.0.tgz#f8cb198c8e7dd2124beddc2457571329096b06e7" |
9400 | integrity sha512-keuNEbNSnsOTOuGCt3UJW69jDE3O4P+UHAakO7vSeFMnjaitcmlbij/a3oNb9g1Y1KvSKH/7O1R2PQ4m4TRylw== | 8139 | integrity sha512-v1yFnE4+u9za42gG/b/081E7uNW9mUj3qtkmelLbW5YPROZzSH/KUUyJu9Wt8vxFJcT9otL/eZopS0YK1L5yPQ== |
9401 | dependencies: | 8140 | dependencies: |
9402 | "@babel/runtime" "7.0.0" | 8141 | "@babel/runtime" "^7.0.0" |
9403 | fn-name "~2.0.1" | 8142 | fn-name "~2.0.1" |
9404 | lodash "^4.17.10" | 8143 | lodash "^4.17.11" |
9405 | property-expr "^1.5.0" | 8144 | property-expr "^1.5.0" |
9406 | synchronous-promise "^2.0.5" | 8145 | synchronous-promise "^2.0.6" |
9407 | toposort "^2.0.2" | 8146 | toposort "^2.0.2" |
9408 | 8147 | ||
9409 | z-schema@^3.24.2: | 8148 | z-schema@^3.24.2: |