diff options
504 files changed, 8224 insertions, 5531 deletions
diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..a86c5bbba --- /dev/null +++ b/.eslintrc.json | |||
@@ -0,0 +1,88 @@ | |||
1 | { | ||
2 | "extends": "standard-with-typescript", | ||
3 | "rules": { | ||
4 | "eol-last": [ | ||
5 | "error", | ||
6 | "always" | ||
7 | ], | ||
8 | "indent": "off", | ||
9 | "no-lone-blocks": "off", | ||
10 | "no-mixed-operators": "off", | ||
11 | "max-len": [ | ||
12 | "error", | ||
13 | { | ||
14 | "code": 140 | ||
15 | } | ||
16 | ], | ||
17 | "array-bracket-spacing": [ | ||
18 | "error", | ||
19 | "always" | ||
20 | ], | ||
21 | "quote-props": [ | ||
22 | "error", | ||
23 | "consistent-as-needed" | ||
24 | ], | ||
25 | "padded-blocks": "off", | ||
26 | "no-async-promise-executor": "off", | ||
27 | "dot-notation": "off", | ||
28 | "promise/param-names": "off", | ||
29 | "import/first": "off", | ||
30 | "operator-linebreak": [ | ||
31 | "error", | ||
32 | "after", | ||
33 | { | ||
34 | "overrides": { | ||
35 | "?": "before", | ||
36 | ":": "before" | ||
37 | } | ||
38 | } | ||
39 | ], | ||
40 | "@typescript-eslint/indent": [ | ||
41 | "error", | ||
42 | 2, | ||
43 | { | ||
44 | "SwitchCase": 1, | ||
45 | "MemberExpression": "off" | ||
46 | } | ||
47 | ], | ||
48 | "@typescript-eslint/consistent-type-assertions": [ | ||
49 | "error", | ||
50 | { | ||
51 | "assertionStyle": "as" | ||
52 | } | ||
53 | ], | ||
54 | "@typescript-eslint/array-type": [ | ||
55 | "error", | ||
56 | { | ||
57 | "default": "array" | ||
58 | } | ||
59 | ], | ||
60 | "@typescript-eslint/restrict-template-expressions": [ | ||
61 | "off", | ||
62 | { | ||
63 | "allowNumber": "true" | ||
64 | } | ||
65 | ], | ||
66 | "@typescript-eslint/quotes": "off", | ||
67 | "@typescript-eslint/no-var-requires": "off", | ||
68 | "@typescript-eslint/explicit-function-return-type": "off", | ||
69 | "@typescript-eslint/promise-function-async": "off", | ||
70 | "@typescript-eslint/no-dynamic-delete": "off", | ||
71 | "@typescript-eslint/strict-boolean-expressions": "off", | ||
72 | "@typescript-eslint/consistent-type-definitions": "off", | ||
73 | "@typescript-eslint/no-misused-promises": "off", | ||
74 | "@typescript-eslint/no-namespace": "off", | ||
75 | "@typescript-eslint/no-extraneous-class": "off", | ||
76 | // bugged but useful | ||
77 | "@typescript-eslint/restrict-plus-operands": "off" | ||
78 | }, | ||
79 | "ignorePatterns": [ | ||
80 | "node_modules/" | ||
81 | ], | ||
82 | "parserOptions": { | ||
83 | "project": [ | ||
84 | "./tsconfig.json", | ||
85 | "./server/tools/tsconfig.json" | ||
86 | ] | ||
87 | } | ||
88 | } | ||
diff --git a/.gitignore b/.gitignore index 6ef90385c..07b2fb7ef 100644 --- a/.gitignore +++ b/.gitignore | |||
@@ -12,6 +12,7 @@ yarn-error.log | |||
12 | /test5/ | 12 | /test5/ |
13 | /test6/ | 13 | /test6/ |
14 | /server/tests/fixtures/video_high_bitrate_1080p.mp4 | 14 | /server/tests/fixtures/video_high_bitrate_1080p.mp4 |
15 | /server/tests/fixtures/video_59fps.mp4 | ||
15 | 16 | ||
16 | # Production | 17 | # Production |
17 | /storage/ | 18 | /storage/ |
diff --git a/client/package.json b/client/package.json index cd0a82aa4..66e8990f9 100644 --- a/client/package.json +++ b/client/package.json | |||
@@ -56,7 +56,6 @@ | |||
56 | "@ngx-loading-bar/router": "^4.2.0", | 56 | "@ngx-loading-bar/router": "^4.2.0", |
57 | "@ngx-meta/core": "^7.0.0", | 57 | "@ngx-meta/core": "^7.0.0", |
58 | "@ngx-translate/i18n-polyfill": "^1.0.0", | 58 | "@ngx-translate/i18n-polyfill": "^1.0.0", |
59 | "@streamroot/videojs-hlsjs-plugin": "^1.0.10", | ||
60 | "@types/core-js": "^2.5.2", | 59 | "@types/core-js": "^2.5.2", |
61 | "@types/debug": "^4.1.5", | 60 | "@types/debug": "^4.1.5", |
62 | "@types/hls.js": "^0.12.4", | 61 | "@types/hls.js": "^0.12.4", |
@@ -65,11 +64,11 @@ | |||
65 | "@types/jschannel": "^1.0.0", | 64 | "@types/jschannel": "^1.0.0", |
66 | "@types/linkifyjs": "^2.1.2", | 65 | "@types/linkifyjs": "^2.1.2", |
67 | "@types/lodash-es": "^4.17.0", | 66 | "@types/lodash-es": "^4.17.0", |
68 | "@types/markdown-it": "^0.0.5", | 67 | "@types/markdown-it": "^0.0.9", |
69 | "@types/node": "^10.9.2", | 68 | "@types/node": "^10.9.2", |
70 | "@types/sanitize-html": "1.18.0", | 69 | "@types/sanitize-html": "1.18.0", |
71 | "@types/socket.io-client": "^1.4.32", | 70 | "@types/socket.io-client": "^1.4.32", |
72 | "@types/video.js": "^7.2.5", | 71 | "@types/video.js": "^7.3.3", |
73 | "@types/webtorrent": "^0.107.0", | 72 | "@types/webtorrent": "^0.107.0", |
74 | "angular2-hotkeys": "^2.1.2", | 73 | "angular2-hotkeys": "^2.1.2", |
75 | "angularx-qrcode": "1.6.4", | 74 | "angularx-qrcode": "1.6.4", |
@@ -77,6 +76,7 @@ | |||
77 | "bootstrap": "^4.1.3", | 76 | "bootstrap": "^4.1.3", |
78 | "buffer": "^5.1.0", | 77 | "buffer": "^5.1.0", |
79 | "cache-chunk-store": "^3.0.0", | 78 | "cache-chunk-store": "^3.0.0", |
79 | "chart.js": "^2.9.3", | ||
80 | "codelyzer": "^5.0.1", | 80 | "codelyzer": "^5.0.1", |
81 | "core-js": "^3.1.4", | 81 | "core-js": "^3.1.4", |
82 | "css-loader": "^3.1.0", | 82 | "css-loader": "^3.1.0", |
@@ -132,6 +132,7 @@ | |||
132 | "videojs-dock": "^2.0.2", | 132 | "videojs-dock": "^2.0.2", |
133 | "videojs-hotkeys": "^0.2.21", | 133 | "videojs-hotkeys": "^0.2.21", |
134 | "videostream": "~3.2.1", | 134 | "videostream": "~3.2.1", |
135 | "vtt.js": "^0.13.0", | ||
135 | "webpack-bundle-analyzer": "^3.0.2", | 136 | "webpack-bundle-analyzer": "^3.0.2", |
136 | "webpack-cli": "^3.0.8", | 137 | "webpack-cli": "^3.0.8", |
137 | "webtorrent": "^0.107.16", | 138 | "webtorrent": "^0.107.16", |
diff --git a/client/src/app/+about/about-instance/about-instance.component.ts b/client/src/app/+about/about-instance/about-instance.component.ts index 87beb13da..c8c156105 100644 --- a/client/src/app/+about/about-instance/about-instance.component.ts +++ b/client/src/app/+about/about-instance/about-instance.component.ts | |||
@@ -1,12 +1,10 @@ | |||
1 | import { Component, OnInit, ViewChild } from '@angular/core' | 1 | import { Component, OnInit, ViewChild } from '@angular/core' |
2 | import { Notifier, ServerService } from '@app/core' | 2 | import { Notifier, ServerService } from '@app/core' |
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
4 | import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' | 3 | import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' |
5 | import { InstanceService } from '@app/shared/instance/instance.service' | 4 | import { InstanceService } from '@app/shared/instance/instance.service' |
6 | import { MarkdownService } from '@app/shared/renderer' | ||
7 | import { forkJoin } from 'rxjs' | ||
8 | import { map, switchMap } from 'rxjs/operators' | ||
9 | import { ServerConfig } from '@shared/models' | 5 | import { ServerConfig } from '@shared/models' |
6 | import { ActivatedRoute } from '@angular/router' | ||
7 | import { ResolverData } from './about-instance.resolver' | ||
10 | 8 | ||
11 | @Component({ | 9 | @Component({ |
12 | selector: 'my-about-instance', | 10 | selector: 'my-about-instance', |
@@ -37,11 +35,10 @@ export class AboutInstanceComponent implements OnInit { | |||
37 | serverConfig: ServerConfig | 35 | serverConfig: ServerConfig |
38 | 36 | ||
39 | constructor ( | 37 | constructor ( |
38 | private route: ActivatedRoute, | ||
40 | private notifier: Notifier, | 39 | private notifier: Notifier, |
41 | private serverService: ServerService, | 40 | private serverService: ServerService, |
42 | private instanceService: InstanceService, | 41 | private instanceService: InstanceService |
43 | private markdownService: MarkdownService, | ||
44 | private i18n: I18n | ||
45 | ) {} | 42 | ) {} |
46 | 43 | ||
47 | get instanceName () { | 44 | get instanceName () { |
@@ -56,35 +53,23 @@ export class AboutInstanceComponent implements OnInit { | |||
56 | return this.serverConfig.instance.isNSFW | 53 | return this.serverConfig.instance.isNSFW |
57 | } | 54 | } |
58 | 55 | ||
59 | ngOnInit () { | 56 | async ngOnInit () { |
60 | this.serverConfig = this.serverService.getTmpConfig() | 57 | this.serverConfig = this.serverService.getTmpConfig() |
61 | this.serverService.getConfig() | 58 | this.serverService.getConfig() |
62 | .subscribe(config => this.serverConfig = config) | 59 | .subscribe(config => this.serverConfig = config) |
63 | 60 | ||
64 | this.instanceService.getAbout() | 61 | const { about, languages, categories }: ResolverData = this.route.snapshot.data.instanceData |
65 | .pipe( | 62 | |
66 | switchMap(about => { | 63 | this.languages = languages |
67 | return forkJoin([ | 64 | this.categories = categories |
68 | this.instanceService.buildTranslatedLanguages(about), | 65 | |
69 | this.instanceService.buildTranslatedCategories(about) | 66 | this.shortDescription = about.instance.shortDescription |
70 | ]).pipe(map(([ languages, categories ]) => ({ about, languages, categories }))) | 67 | |
71 | }) | 68 | this.creationReason = about.instance.creationReason |
72 | ).subscribe( | 69 | this.maintenanceLifetime = about.instance.maintenanceLifetime |
73 | async ({ about, languages, categories }) => { | 70 | this.businessModel = about.instance.businessModel |
74 | this.languages = languages | 71 | |
75 | this.categories = categories | 72 | this.html = await this.instanceService.buildHtml(about) |
76 | |||
77 | this.shortDescription = about.instance.shortDescription | ||
78 | |||
79 | this.creationReason = about.instance.creationReason | ||
80 | this.maintenanceLifetime = about.instance.maintenanceLifetime | ||
81 | this.businessModel = about.instance.businessModel | ||
82 | |||
83 | this.html = await this.instanceService.buildHtml(about) | ||
84 | }, | ||
85 | |||
86 | () => this.notifier.error(this.i18n('Cannot get about information from server')) | ||
87 | ) | ||
88 | } | 73 | } |
89 | 74 | ||
90 | openContactModal () { | 75 | openContactModal () { |
diff --git a/client/src/app/+about/about-instance/about-instance.resolver.ts b/client/src/app/+about/about-instance/about-instance.resolver.ts new file mode 100644 index 000000000..94c6abe5a --- /dev/null +++ b/client/src/app/+about/about-instance/about-instance.resolver.ts | |||
@@ -0,0 +1,27 @@ | |||
1 | import { Injectable } from '@angular/core' | ||
2 | import { ActivatedRouteSnapshot, Resolve } from '@angular/router' | ||
3 | import { map, switchMap } from 'rxjs/operators' | ||
4 | import { forkJoin } from 'rxjs' | ||
5 | import { InstanceService } from '@app/shared/instance/instance.service' | ||
6 | import { About } from '@shared/models/server' | ||
7 | |||
8 | export type ResolverData = { about: About, languages: string[], categories: string[] } | ||
9 | |||
10 | @Injectable() | ||
11 | export class AboutInstanceResolver implements Resolve<any> { | ||
12 | constructor ( | ||
13 | private instanceService: InstanceService | ||
14 | ) {} | ||
15 | |||
16 | resolve (route: ActivatedRouteSnapshot) { | ||
17 | return this.instanceService.getAbout() | ||
18 | .pipe( | ||
19 | switchMap(about => { | ||
20 | return forkJoin([ | ||
21 | this.instanceService.buildTranslatedLanguages(about), | ||
22 | this.instanceService.buildTranslatedCategories(about) | ||
23 | ]).pipe(map(([ languages, categories ]) => ({ about, languages, categories }))) | ||
24 | }) | ||
25 | ) | ||
26 | } | ||
27 | } | ||
diff --git a/client/src/app/+about/about-routing.module.ts b/client/src/app/+about/about-routing.module.ts index 33e5070cb..91ccb846f 100644 --- a/client/src/app/+about/about-routing.module.ts +++ b/client/src/app/+about/about-routing.module.ts | |||
@@ -5,6 +5,7 @@ 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 | import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component' |
8 | import { AboutInstanceResolver } from '@app/+about/about-instance/about-instance.resolver' | ||
8 | 9 | ||
9 | const aboutRoutes: Routes = [ | 10 | const aboutRoutes: Routes = [ |
10 | { | 11 | { |
@@ -24,6 +25,9 @@ const aboutRoutes: Routes = [ | |||
24 | meta: { | 25 | meta: { |
25 | title: 'About this instance' | 26 | title: 'About this instance' |
26 | } | 27 | } |
28 | }, | ||
29 | resolve: { | ||
30 | instanceData: AboutInstanceResolver | ||
27 | } | 31 | } |
28 | }, | 32 | }, |
29 | { | 33 | { |
diff --git a/client/src/app/+about/about.module.ts b/client/src/app/+about/about.module.ts index 14bf76e55..84d697540 100644 --- a/client/src/app/+about/about.module.ts +++ b/client/src/app/+about/about.module.ts | |||
@@ -7,6 +7,7 @@ import { AboutPeertubeComponent } from '@app/+about/about-peertube/about-peertub | |||
7 | import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' | 7 | import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-admin-modal.component' |
8 | import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component' | 8 | import { AboutFollowsComponent } from '@app/+about/about-follows/about-follows.component' |
9 | import { AboutPeertubeContributorsComponent } from '@app/+about/about-peertube/about-peertube-contributors.component' | 9 | import { AboutPeertubeContributorsComponent } from '@app/+about/about-peertube/about-peertube-contributors.component' |
10 | import { AboutInstanceResolver } from '@app/+about/about-instance/about-instance.resolver' | ||
10 | 11 | ||
11 | @NgModule({ | 12 | @NgModule({ |
12 | imports: [ | 13 | imports: [ |
@@ -28,6 +29,7 @@ import { AboutPeertubeContributorsComponent } from '@app/+about/about-peertube/a | |||
28 | ], | 29 | ], |
29 | 30 | ||
30 | providers: [ | 31 | providers: [ |
32 | AboutInstanceResolver | ||
31 | ] | 33 | ] |
32 | }) | 34 | }) |
33 | export class AboutModule { } | 35 | export class AboutModule { } |
diff --git a/client/src/app/+admin/admin.component.html b/client/src/app/+admin/admin.component.html index 9a3d90c18..0d06aaedc 100644 --- a/client/src/app/+admin/admin.component.html +++ b/client/src/app/+admin/admin.component.html | |||
@@ -5,7 +5,7 @@ | |||
5 | </a> | 5 | </a> |
6 | 6 | ||
7 | <a i18n *ngIf="hasServerFollowRight()" routerLink="/admin/follows" routerLinkActive="active" class="title-page"> | 7 | <a i18n *ngIf="hasServerFollowRight()" routerLink="/admin/follows" routerLinkActive="active" class="title-page"> |
8 | Manage follows | 8 | Follows & redundancies |
9 | </a> | 9 | </a> |
10 | 10 | ||
11 | <a i18n *ngIf="hasVideoAbusesRight() || hasVideoBlacklistRight()" routerLink="/admin/moderation" routerLinkActive="active" class="title-page"> | 11 | <a i18n *ngIf="hasVideoAbusesRight() || hasVideoBlacklistRight()" routerLink="/admin/moderation" routerLinkActive="active" class="title-page"> |
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index 9c56b5750..fdbe70314 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 } from './follows' | 8 | import { FollowersListComponent, FollowingAddComponent, FollowsComponent, VideoRedundanciesListComponent } 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 { |
@@ -16,7 +16,6 @@ import { | |||
16 | } from './moderation' | 16 | } from './moderation' |
17 | import { ModerationComponent } from '@app/+admin/moderation/moderation.component' | 17 | import { ModerationComponent } from '@app/+admin/moderation/moderation.component' |
18 | import { RedundancyCheckboxComponent } from '@app/+admin/follows/shared/redundancy-checkbox.component' | 18 | import { RedundancyCheckboxComponent } from '@app/+admin/follows/shared/redundancy-checkbox.component' |
19 | import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service' | ||
20 | import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist' | 19 | import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist' |
21 | import { JobsComponent } from '@app/+admin/system/jobs/jobs.component' | 20 | import { JobsComponent } from '@app/+admin/system/jobs/jobs.component' |
22 | import { JobService, LogsComponent, LogsService, SystemComponent } from '@app/+admin/system' | 21 | import { JobService, LogsComponent, LogsService, SystemComponent } from '@app/+admin/system' |
@@ -27,13 +26,18 @@ import { PluginSearchComponent } from '@app/+admin/plugins/plugin-search/plugin- | |||
27 | import { PluginShowInstalledComponent } from '@app/+admin/plugins/plugin-show-installed/plugin-show-installed.component' | 26 | import { PluginShowInstalledComponent } from '@app/+admin/plugins/plugin-show-installed/plugin-show-installed.component' |
28 | import { SelectButtonModule } from 'primeng/selectbutton' | 27 | import { SelectButtonModule } from 'primeng/selectbutton' |
29 | import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' | 28 | import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' |
29 | import { VideoRedundancyInformationComponent } from '@app/+admin/follows/video-redundancies-list/video-redundancy-information.component' | ||
30 | import { ChartModule } from 'primeng/chart' | ||
30 | 31 | ||
31 | @NgModule({ | 32 | @NgModule({ |
32 | imports: [ | 33 | imports: [ |
33 | AdminRoutingModule, | 34 | AdminRoutingModule, |
35 | |||
36 | SharedModule, | ||
37 | |||
34 | TableModule, | 38 | TableModule, |
35 | SelectButtonModule, | 39 | SelectButtonModule, |
36 | SharedModule | 40 | ChartModule |
37 | ], | 41 | ], |
38 | 42 | ||
39 | declarations: [ | 43 | declarations: [ |
@@ -44,6 +48,8 @@ import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' | |||
44 | FollowersListComponent, | 48 | FollowersListComponent, |
45 | FollowingListComponent, | 49 | FollowingListComponent, |
46 | RedundancyCheckboxComponent, | 50 | RedundancyCheckboxComponent, |
51 | VideoRedundanciesListComponent, | ||
52 | VideoRedundancyInformationComponent, | ||
47 | 53 | ||
48 | UsersComponent, | 54 | UsersComponent, |
49 | UserCreateComponent, | 55 | UserCreateComponent, |
@@ -78,7 +84,6 @@ import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' | |||
78 | ], | 84 | ], |
79 | 85 | ||
80 | providers: [ | 86 | providers: [ |
81 | RedundancyService, | ||
82 | JobService, | 87 | JobService, |
83 | LogsService, | 88 | LogsService, |
84 | DebugService, | 89 | DebugService, |
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 915d60090..d806ea355 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 | |||
@@ -234,6 +234,9 @@ | |||
234 | inputName="signupEnabled" formControlName="enabled" | 234 | inputName="signupEnabled" formControlName="enabled" |
235 | i18n-labelText labelText="Signup enabled" | 235 | i18n-labelText labelText="Signup enabled" |
236 | > | 236 | > |
237 | <ng-container ngProjectAs="description"> | ||
238 | <span i18n>⚠️ This functionality requires a lot of attention and extra moderation.</span> | ||
239 | </ng-container> | ||
237 | <ng-container ngProjectAs="extra"> | 240 | <ng-container ngProjectAs="extra"> |
238 | <my-peertube-checkbox [ngClass]="{ 'disabled-checkbox-extra': !isSignupEnabled() }" | 241 | <my-peertube-checkbox [ngClass]="{ 'disabled-checkbox-extra': !isSignupEnabled() }" |
239 | inputName="signupRequiresEmailVerification" formControlName="requiresEmailVerification" | 242 | inputName="signupRequiresEmailVerification" formControlName="requiresEmailVerification" |
@@ -243,10 +246,11 @@ | |||
243 | <div [ngClass]="{ 'disabled-checkbox-extra': !isSignupEnabled() }" class="mt-3"> | 246 | <div [ngClass]="{ 'disabled-checkbox-extra': !isSignupEnabled() }" class="mt-3"> |
244 | <label i18n for="signupLimit">Signup limit</label> | 247 | <label i18n for="signupLimit">Signup limit</label> |
245 | <input | 248 | <input |
246 | type="text" id="signupLimit" | 249 | type="number" min="-1" id="signupLimit" |
247 | formControlName="limit" [ngClass]="{ 'input-error': formErrors['signup.limit'] }" | 250 | formControlName="limit" [ngClass]="{ 'input-error': formErrors['signup.limit'] }" |
248 | > | 251 | > |
249 | <div *ngIf="formErrors.signup.limit" class="form-error">{{ formErrors.signup.limit }}</div> | 252 | <div *ngIf="formErrors.signup.limit" class="form-error">{{ formErrors.signup.limit }}</div> |
253 | <small *ngIf="form.value['signup']['limit'] === -1" class="text-muted">Signup won't be limited to a fixed number of users.</small> | ||
250 | </div> | 254 | </div> |
251 | </ng-container> | 255 | </ng-container> |
252 | </my-peertube-checkbox> | 256 | </my-peertube-checkbox> |
@@ -318,7 +322,7 @@ | |||
318 | i18n-labelText labelText="Blacklist new videos automatically" | 322 | i18n-labelText labelText="Blacklist new videos automatically" |
319 | > | 323 | > |
320 | <ng-container ngProjectAs="description"> | 324 | <ng-container ngProjectAs="description"> |
321 | <span i18n>Videos of regular users will stay private until a moderator reviews them. Can be overriden per user.</span> | 325 | <span i18n>Unless a user is marked as trusted, their videos will stay private until a moderator reviews them.</span> |
322 | </ng-container> | 326 | </ng-container> |
323 | </my-peertube-checkbox> | 327 | </my-peertube-checkbox> |
324 | </div> | 328 | </div> |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss index 60d608028..dd70f1c06 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.scss | |||
@@ -10,6 +10,11 @@ input[type=text] { | |||
10 | display: block; | 10 | display: block; |
11 | } | 11 | } |
12 | 12 | ||
13 | input[type=number] { | ||
14 | @include peertube-input-text(315px); | ||
15 | display: block; | ||
16 | } | ||
17 | |||
13 | input[type=checkbox] { | 18 | input[type=checkbox] { |
14 | @include peertube-checkbox(1px); | 19 | @include peertube-checkbox(1px); |
15 | } | 20 | } |
diff --git a/client/src/app/+admin/follows/following-add/following-add.component.scss b/client/src/app/+admin/follows/following-add/following-add.component.scss index 1baddc95f..df104c14e 100644 --- a/client/src/app/+admin/follows/following-add/following-add.component.scss +++ b/client/src/app/+admin/follows/following-add/following-add.component.scss | |||
@@ -7,7 +7,7 @@ textarea { | |||
7 | 7 | ||
8 | .form-control { | 8 | .form-control { |
9 | &, &:focus { | 9 | &, &:focus { |
10 | background-color: var(--inputColor); | 10 | background-color: var(--inputBackgroundColor); |
11 | color: var(--mainForegroundColor); | 11 | color: var(--mainForegroundColor); |
12 | } | 12 | } |
13 | } | 13 | } |
diff --git a/client/src/app/+admin/follows/follows.component.html b/client/src/app/+admin/follows/follows.component.html index 21d477132..46581daf9 100644 --- a/client/src/app/+admin/follows/follows.component.html +++ b/client/src/app/+admin/follows/follows.component.html | |||
@@ -1,5 +1,5 @@ | |||
1 | <div class="admin-sub-header"> | 1 | <div class="admin-sub-header"> |
2 | <div i18n class="form-sub-title">Manage follows</div> | 2 | <div i18n class="form-sub-title">Follows & redundancies</div> |
3 | 3 | ||
4 | <div class="admin-sub-nav"> | 4 | <div class="admin-sub-nav"> |
5 | <a i18n routerLink="following-list" routerLinkActive="active">Following</a> | 5 | <a i18n routerLink="following-list" routerLinkActive="active">Following</a> |
@@ -7,7 +7,9 @@ | |||
7 | <a i18n routerLink="following-add" routerLinkActive="active">Follow</a> | 7 | <a i18n routerLink="following-add" routerLinkActive="active">Follow</a> |
8 | 8 | ||
9 | <a i18n routerLink="followers-list" routerLinkActive="active">Followers</a> | 9 | <a i18n routerLink="followers-list" routerLinkActive="active">Followers</a> |
10 | |||
11 | <a i18n routerLink="video-redundancies-list" routerLinkActive="active">Video redundancies</a> | ||
10 | </div> | 12 | </div> |
11 | </div> | 13 | </div> |
12 | 14 | ||
13 | <router-outlet></router-outlet> \ No newline at end of file | 15 | <router-outlet></router-outlet> |
diff --git a/client/src/app/+admin/follows/follows.routes.ts b/client/src/app/+admin/follows/follows.routes.ts index e84c79e82..298733eb0 100644 --- a/client/src/app/+admin/follows/follows.routes.ts +++ b/client/src/app/+admin/follows/follows.routes.ts | |||
@@ -6,6 +6,7 @@ import { FollowingAddComponent } from './following-add' | |||
6 | import { FollowersListComponent } from './followers-list' | 6 | import { FollowersListComponent } from './followers-list' |
7 | import { UserRight } from '../../../../../shared' | 7 | import { UserRight } from '../../../../../shared' |
8 | import { FollowingListComponent } from './following-list/following-list.component' | 8 | import { FollowingListComponent } from './following-list/following-list.component' |
9 | import { VideoRedundanciesListComponent } from '@app/+admin/follows/video-redundancies-list' | ||
9 | 10 | ||
10 | export const FollowsRoutes: Routes = [ | 11 | export const FollowsRoutes: Routes = [ |
11 | { | 12 | { |
@@ -47,6 +48,10 @@ export const FollowsRoutes: Routes = [ | |||
47 | title: 'Add follow' | 48 | title: 'Add follow' |
48 | } | 49 | } |
49 | } | 50 | } |
51 | }, | ||
52 | { | ||
53 | path: 'video-redundancies-list', | ||
54 | component: VideoRedundanciesListComponent | ||
50 | } | 55 | } |
51 | ] | 56 | ] |
52 | } | 57 | } |
diff --git a/client/src/app/+admin/follows/index.ts b/client/src/app/+admin/follows/index.ts index e94f33710..4fcb35cb1 100644 --- a/client/src/app/+admin/follows/index.ts +++ b/client/src/app/+admin/follows/index.ts | |||
@@ -1,5 +1,6 @@ | |||
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 './video-redundancies-list' | ||
4 | export * from './follows.component' | 5 | export * from './follows.component' |
5 | export * from './follows.routes' | 6 | export * from './follows.routes' |
diff --git a/client/src/app/+admin/follows/shared/redundancy-checkbox.component.ts b/client/src/app/+admin/follows/shared/redundancy-checkbox.component.ts index fa1da26bf..9d7883d97 100644 --- a/client/src/app/+admin/follows/shared/redundancy-checkbox.component.ts +++ b/client/src/app/+admin/follows/shared/redundancy-checkbox.component.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Component, Input } from '@angular/core' | 1 | import { Component, Input } from '@angular/core' |
2 | import { Notifier } from '@app/core' | 2 | import { Notifier } from '@app/core' |
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | 3 | import { I18n } from '@ngx-translate/i18n-polyfill' |
4 | import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service' | 4 | import { RedundancyService } from '@app/shared/video/redundancy.service' |
5 | 5 | ||
6 | @Component({ | 6 | @Component({ |
7 | selector: 'my-redundancy-checkbox', | 7 | selector: 'my-redundancy-checkbox', |
diff --git a/client/src/app/+admin/follows/shared/redundancy.service.ts b/client/src/app/+admin/follows/shared/redundancy.service.ts deleted file mode 100644 index 87ae01c04..000000000 --- a/client/src/app/+admin/follows/shared/redundancy.service.ts +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | import { catchError, map } from 'rxjs/operators' | ||
2 | import { HttpClient } from '@angular/common/http' | ||
3 | import { Injectable } from '@angular/core' | ||
4 | import { RestExtractor } from '@app/shared' | ||
5 | import { environment } from '../../../../environments/environment' | ||
6 | |||
7 | @Injectable() | ||
8 | export class RedundancyService { | ||
9 | static BASE_USER_SUBSCRIPTIONS_URL = environment.apiUrl + '/api/v1/server/redundancy' | ||
10 | |||
11 | constructor ( | ||
12 | private authHttp: HttpClient, | ||
13 | private restExtractor: RestExtractor | ||
14 | ) { } | ||
15 | |||
16 | updateRedundancy (host: string, redundancyAllowed: boolean) { | ||
17 | const url = RedundancyService.BASE_USER_SUBSCRIPTIONS_URL + '/' + host | ||
18 | |||
19 | const body = { redundancyAllowed } | ||
20 | |||
21 | return this.authHttp.put(url, body) | ||
22 | .pipe( | ||
23 | map(this.restExtractor.extractDataBool), | ||
24 | catchError(err => this.restExtractor.handleError(err)) | ||
25 | ) | ||
26 | } | ||
27 | |||
28 | } | ||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/index.ts b/client/src/app/+admin/follows/video-redundancies-list/index.ts new file mode 100644 index 000000000..6a7c7f483 --- /dev/null +++ b/client/src/app/+admin/follows/video-redundancies-list/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './video-redundancies-list.component' | |||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html new file mode 100644 index 000000000..80c66ec60 --- /dev/null +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html | |||
@@ -0,0 +1,82 @@ | |||
1 | <div class="admin-sub-header"> | ||
2 | <div i18n class="form-sub-title">Video redundancies list</div> | ||
3 | |||
4 | <div class="select-filter-block"> | ||
5 | <label for="displayType" i18n>Display</label> | ||
6 | |||
7 | <div class="peertube-select-container"> | ||
8 | <select id="displayType" name="displayType" [(ngModel)]="displayType" (ngModelChange)="onDisplayTypeChanged()"> | ||
9 | <option value="my-videos">My videos duplicated by remote instances</option> | ||
10 | <option value="remote-videos">Remote videos duplicated by my instance</option> | ||
11 | </select> | ||
12 | </div> | ||
13 | </div> | ||
14 | </div> | ||
15 | |||
16 | <p-table | ||
17 | [value]="videoRedundancies" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | ||
18 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" | ||
19 | > | ||
20 | <ng-template pTemplate="header"> | ||
21 | <tr> | ||
22 | <th i18n *ngIf="isDisplayingRemoteVideos()">Strategy</th> | ||
23 | <th i18n pSortableColumn="name">Video name <p-sortIcon field="name"></p-sortIcon></th> | ||
24 | <th i18n>Video URL</th> | ||
25 | <th i18n *ngIf="isDisplayingRemoteVideos()">Total size</th> | ||
26 | <th></th> | ||
27 | </tr> | ||
28 | </ng-template> | ||
29 | |||
30 | <ng-template pTemplate="body" let-redundancy> | ||
31 | <tr class="expander" [pRowToggler]="redundancy"> | ||
32 | <td *ngIf="isDisplayingRemoteVideos()">{{ getRedundancyStrategy(redundancy) }}</td> | ||
33 | |||
34 | <td>{{ redundancy.name }}</td> | ||
35 | |||
36 | <td> | ||
37 | <a target="_blank" rel="noopener noreferrer" [href]="redundancy.url">{{ redundancy.url }}</a> | ||
38 | </td> | ||
39 | |||
40 | <td *ngIf="isDisplayingRemoteVideos()">{{ getTotalSize(redundancy) | bytes: 1 }}</td> | ||
41 | |||
42 | <td class="action-cell"> | ||
43 | <my-delete-button (click)="removeRedundancy(redundancy)"></my-delete-button> | ||
44 | </td> | ||
45 | </tr> | ||
46 | </ng-template> | ||
47 | |||
48 | <ng-template pTemplate="rowexpansion" let-redundancy> | ||
49 | <tr> | ||
50 | <td colspan="2"> | ||
51 | <div *ngFor="let file of redundancy.redundancies.files" class="expansion-block"> | ||
52 | <my-video-redundancy-information [redundancyElement]="file"></my-video-redundancy-information> | ||
53 | </div> | ||
54 | </td> | ||
55 | </tr> | ||
56 | |||
57 | <tr> | ||
58 | <td colspan="2"> | ||
59 | <div *ngFor="let playlist of redundancy.redundancies.streamingPlaylists"> | ||
60 | <my-video-redundancy-information [redundancyElement]="playlist"></my-video-redundancy-information> | ||
61 | </div> | ||
62 | </td> | ||
63 | </tr> | ||
64 | </ng-template> | ||
65 | </p-table> | ||
66 | |||
67 | |||
68 | <div class="redundancies-charts" *ngIf="isDisplayingRemoteVideos()"> | ||
69 | <div class="form-sub-title" i18n>Enabled strategies stats</div> | ||
70 | |||
71 | <div class="chart-blocks"> | ||
72 | |||
73 | <div *ngIf="noRedundancies" i18n class="no-results"> | ||
74 | No redundancy strategy is enabled on your instance. | ||
75 | </div> | ||
76 | |||
77 | <div class="chart-block" *ngFor="let r of redundanciesGraphsData"> | ||
78 | <p-chart type="pie" [data]="r.graphData" [options]="r.options" width="300px" height="300px"></p-chart> | ||
79 | </div> | ||
80 | |||
81 | </div> | ||
82 | </div> | ||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.scss b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.scss new file mode 100644 index 000000000..05018c281 --- /dev/null +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.scss | |||
@@ -0,0 +1,37 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .expansion-block { | ||
5 | margin-bottom: 20px; | ||
6 | } | ||
7 | |||
8 | .admin-sub-header { | ||
9 | align-items: flex-end; | ||
10 | |||
11 | .select-filter-block { | ||
12 | &:not(:last-child) { | ||
13 | margin-right: 10px; | ||
14 | } | ||
15 | |||
16 | label { | ||
17 | margin-bottom: 2px; | ||
18 | } | ||
19 | |||
20 | .peertube-select-container { | ||
21 | @include peertube-select-container(auto); | ||
22 | } | ||
23 | } | ||
24 | } | ||
25 | |||
26 | .redundancies-charts { | ||
27 | margin-top: 50px; | ||
28 | |||
29 | .chart-blocks { | ||
30 | display: flex; | ||
31 | justify-content: center; | ||
32 | |||
33 | .chart-block { | ||
34 | margin: 0 20px; | ||
35 | } | ||
36 | } | ||
37 | } | ||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts new file mode 100644 index 000000000..4b41d1d86 --- /dev/null +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.ts | |||
@@ -0,0 +1,178 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { Notifier, ServerService } from '@app/core' | ||
3 | import { SortMeta } from 'primeng/api' | ||
4 | import { ConfirmService } from '../../../core/confirm/confirm.service' | ||
5 | import { RestPagination, RestTable } from '../../../shared' | ||
6 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
7 | import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' | ||
8 | import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage' | ||
9 | import { VideosRedundancyStats } from '@shared/models/server' | ||
10 | import { BytesPipe } from 'ngx-pipes' | ||
11 | import { RedundancyService } from '@app/shared/video/redundancy.service' | ||
12 | |||
13 | @Component({ | ||
14 | selector: 'my-video-redundancies-list', | ||
15 | templateUrl: './video-redundancies-list.component.html', | ||
16 | styleUrls: [ './video-redundancies-list.component.scss' ] | ||
17 | }) | ||
18 | export class VideoRedundanciesListComponent extends RestTable implements OnInit { | ||
19 | private static LOCAL_STORAGE_DISPLAY_TYPE = 'video-redundancies-list-display-type' | ||
20 | |||
21 | videoRedundancies: VideoRedundancy[] = [] | ||
22 | totalRecords = 0 | ||
23 | rowsPerPage = 10 | ||
24 | |||
25 | sort: SortMeta = { field: 'name', order: 1 } | ||
26 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
27 | displayType: VideoRedundanciesTarget = 'my-videos' | ||
28 | |||
29 | redundanciesGraphsData: { stats: VideosRedundancyStats, graphData: object, options: object }[] = [] | ||
30 | |||
31 | noRedundancies = false | ||
32 | |||
33 | private bytesPipe: BytesPipe | ||
34 | |||
35 | constructor ( | ||
36 | private notifier: Notifier, | ||
37 | private confirmService: ConfirmService, | ||
38 | private redundancyService: RedundancyService, | ||
39 | private serverService: ServerService, | ||
40 | private i18n: I18n | ||
41 | ) { | ||
42 | super() | ||
43 | |||
44 | this.bytesPipe = new BytesPipe() | ||
45 | } | ||
46 | |||
47 | ngOnInit () { | ||
48 | this.loadSelectLocalStorage() | ||
49 | |||
50 | this.initialize() | ||
51 | |||
52 | this.serverService.getServerStats() | ||
53 | .subscribe(res => { | ||
54 | const redundancies = res.videosRedundancy | ||
55 | |||
56 | if (redundancies.length === 0) this.noRedundancies = true | ||
57 | |||
58 | for (const r of redundancies) { | ||
59 | this.buildPieData(r) | ||
60 | } | ||
61 | }) | ||
62 | } | ||
63 | |||
64 | isDisplayingRemoteVideos () { | ||
65 | return this.displayType === 'remote-videos' | ||
66 | } | ||
67 | |||
68 | getTotalSize (redundancy: VideoRedundancy) { | ||
69 | return redundancy.redundancies.files.reduce((a, b) => a + b.size, 0) + | ||
70 | redundancy.redundancies.streamingPlaylists.reduce((a, b) => a + b.size, 0) | ||
71 | } | ||
72 | |||
73 | onDisplayTypeChanged () { | ||
74 | this.pagination.start = 0 | ||
75 | this.saveSelectLocalStorage() | ||
76 | |||
77 | this.loadData() | ||
78 | } | ||
79 | |||
80 | getRedundancyStrategy (redundancy: VideoRedundancy) { | ||
81 | if (redundancy.redundancies.files.length !== 0) return redundancy.redundancies.files[0].strategy | ||
82 | if (redundancy.redundancies.streamingPlaylists.length !== 0) return redundancy.redundancies.streamingPlaylists[0].strategy | ||
83 | |||
84 | return '' | ||
85 | } | ||
86 | |||
87 | buildPieData (stats: VideosRedundancyStats) { | ||
88 | const totalSize = stats.totalSize | ||
89 | ? stats.totalSize - stats.totalUsed | ||
90 | : stats.totalUsed | ||
91 | |||
92 | if (totalSize === 0) return | ||
93 | |||
94 | this.redundanciesGraphsData.push({ | ||
95 | stats, | ||
96 | graphData: { | ||
97 | labels: [ this.i18n('Used'), this.i18n('Available') ], | ||
98 | datasets: [ | ||
99 | { | ||
100 | data: [ stats.totalUsed, totalSize ], | ||
101 | backgroundColor: [ | ||
102 | '#FF6384', | ||
103 | '#36A2EB' | ||
104 | ], | ||
105 | hoverBackgroundColor: [ | ||
106 | '#FF6384', | ||
107 | '#36A2EB' | ||
108 | ] | ||
109 | } | ||
110 | ] | ||
111 | }, | ||
112 | options: { | ||
113 | title: { | ||
114 | display: true, | ||
115 | text: stats.strategy | ||
116 | }, | ||
117 | |||
118 | tooltips: { | ||
119 | callbacks: { | ||
120 | label: (tooltipItem: any, data: any) => { | ||
121 | const dataset = data.datasets[tooltipItem.datasetIndex] | ||
122 | let label = data.labels[tooltipItem.index] | ||
123 | if (label) label += ': ' | ||
124 | else label = '' | ||
125 | |||
126 | label += this.bytesPipe.transform(dataset.data[tooltipItem.index], 1) | ||
127 | return label | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | }) | ||
133 | } | ||
134 | |||
135 | async removeRedundancy (redundancy: VideoRedundancy) { | ||
136 | const message = this.i18n('Do you really want to remove this video redundancy?') | ||
137 | const res = await this.confirmService.confirm(message, this.i18n('Remove redundancy')) | ||
138 | if (res === false) return | ||
139 | |||
140 | this.redundancyService.removeVideoRedundancies(redundancy) | ||
141 | .subscribe( | ||
142 | () => { | ||
143 | this.notifier.success(this.i18n('Video redundancies removed!')) | ||
144 | this.loadData() | ||
145 | }, | ||
146 | |||
147 | err => this.notifier.error(err.message) | ||
148 | ) | ||
149 | |||
150 | } | ||
151 | |||
152 | protected loadData () { | ||
153 | const options = { | ||
154 | pagination: this.pagination, | ||
155 | sort: this.sort, | ||
156 | target: this.displayType | ||
157 | } | ||
158 | |||
159 | this.redundancyService.listVideoRedundancies(options) | ||
160 | .subscribe( | ||
161 | resultList => { | ||
162 | this.videoRedundancies = resultList.data | ||
163 | this.totalRecords = resultList.total | ||
164 | }, | ||
165 | |||
166 | err => this.notifier.error(err.message) | ||
167 | ) | ||
168 | } | ||
169 | |||
170 | private loadSelectLocalStorage () { | ||
171 | const displayType = peertubeLocalStorage.getItem(VideoRedundanciesListComponent.LOCAL_STORAGE_DISPLAY_TYPE) | ||
172 | if (displayType) this.displayType = displayType as VideoRedundanciesTarget | ||
173 | } | ||
174 | |||
175 | private saveSelectLocalStorage () { | ||
176 | peertubeLocalStorage.setItem(VideoRedundanciesListComponent.LOCAL_STORAGE_DISPLAY_TYPE, this.displayType) | ||
177 | } | ||
178 | } | ||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancy-information.component.html b/client/src/app/+admin/follows/video-redundancies-list/video-redundancy-information.component.html new file mode 100644 index 000000000..a379520e3 --- /dev/null +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancy-information.component.html | |||
@@ -0,0 +1,24 @@ | |||
1 | <div> | ||
2 | <span class="label">Url</span> | ||
3 | <a target="_blank" rel="noopener noreferrer" [href]="redundancyElement.fileUrl">{{ redundancyElement.fileUrl }}</a> | ||
4 | </div> | ||
5 | |||
6 | <div> | ||
7 | <span class="label">Created on</span> | ||
8 | <span>{{ redundancyElement.createdAt | date: 'medium' }}</span> | ||
9 | </div> | ||
10 | |||
11 | <div> | ||
12 | <span class="label">Expires on</span> | ||
13 | <span>{{ redundancyElement.expiresOn | date: 'medium' }}</span> | ||
14 | </div> | ||
15 | |||
16 | <div> | ||
17 | <span class="label">Size</span> | ||
18 | <span>{{ redundancyElement.size | bytes: 1 }}</span> | ||
19 | </div> | ||
20 | |||
21 | <div *ngIf="redundancyElement.strategy"> | ||
22 | <span class="label">Strategy</span> | ||
23 | <span>{{ redundancyElement.strategy }}</span> | ||
24 | </div> | ||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancy-information.component.scss b/client/src/app/+admin/follows/video-redundancies-list/video-redundancy-information.component.scss new file mode 100644 index 000000000..6b09fbb01 --- /dev/null +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancy-information.component.scss | |||
@@ -0,0 +1,8 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .label { | ||
5 | display: inline-block; | ||
6 | min-width: 100px; | ||
7 | font-weight: $font-semibold; | ||
8 | } | ||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancy-information.component.ts b/client/src/app/+admin/follows/video-redundancies-list/video-redundancy-information.component.ts new file mode 100644 index 000000000..6f3090c08 --- /dev/null +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancy-information.component.ts | |||
@@ -0,0 +1,11 @@ | |||
1 | import { Component, Input } from '@angular/core' | ||
2 | import { FileRedundancyInformation, StreamingPlaylistRedundancyInformation } from '@shared/models' | ||
3 | |||
4 | @Component({ | ||
5 | selector: 'my-video-redundancy-information', | ||
6 | templateUrl: './video-redundancy-information.component.html', | ||
7 | styleUrls: [ './video-redundancy-information.component.scss' ] | ||
8 | }) | ||
9 | export class VideoRedundancyInformationComponent { | ||
10 | @Input() redundancyElement: FileRedundancyInformation | StreamingPlaylistRedundancyInformation | ||
11 | } | ||
diff --git a/client/src/app/+admin/system/jobs/jobs.component.ts b/client/src/app/+admin/system/jobs/jobs.component.ts index 20c8ea71a..bc40452cf 100644 --- a/client/src/app/+admin/system/jobs/jobs.component.ts +++ b/client/src/app/+admin/system/jobs/jobs.component.ts | |||
@@ -16,8 +16,8 @@ import { JobTypeClient } from '../../../../types/job-type-client.type' | |||
16 | styleUrls: [ './jobs.component.scss' ] | 16 | styleUrls: [ './jobs.component.scss' ] |
17 | }) | 17 | }) |
18 | export class JobsComponent extends RestTable implements OnInit { | 18 | export class JobsComponent extends RestTable implements OnInit { |
19 | private static JOB_STATE_LOCAL_STORAGE_STATE = 'jobs-list-state' | 19 | private static LOCAL_STORAGE_STATE = 'jobs-list-state' |
20 | private static JOB_STATE_LOCAL_STORAGE_TYPE = 'jobs-list-type' | 20 | private static LOCAL_STORAGE_TYPE = 'jobs-list-type' |
21 | 21 | ||
22 | jobState: JobStateClient = 'waiting' | 22 | jobState: JobStateClient = 'waiting' |
23 | jobStates: JobStateClient[] = [ 'active', 'completed', 'failed', 'waiting', 'delayed' ] | 23 | jobStates: JobStateClient[] = [ 'active', 'completed', 'failed', 'waiting', 'delayed' ] |
@@ -34,7 +34,8 @@ export class JobsComponent extends RestTable implements OnInit { | |||
34 | 'video-file-import', | 34 | 'video-file-import', |
35 | 'video-import', | 35 | 'video-import', |
36 | 'videos-views', | 36 | 'videos-views', |
37 | 'activitypub-refresher' | 37 | 'activitypub-refresher', |
38 | 'video-redundancy' | ||
38 | ] | 39 | ] |
39 | 40 | ||
40 | jobs: Job[] = [] | 41 | jobs: Job[] = [] |
@@ -77,15 +78,15 @@ export class JobsComponent extends RestTable implements OnInit { | |||
77 | } | 78 | } |
78 | 79 | ||
79 | private loadJobStateAndType () { | 80 | private loadJobStateAndType () { |
80 | const state = peertubeLocalStorage.getItem(JobsComponent.JOB_STATE_LOCAL_STORAGE_STATE) | 81 | const state = peertubeLocalStorage.getItem(JobsComponent.LOCAL_STORAGE_STATE) |
81 | if (state) this.jobState = state as JobState | 82 | if (state) this.jobState = state as JobState |
82 | 83 | ||
83 | const type = peertubeLocalStorage.getItem(JobsComponent.JOB_STATE_LOCAL_STORAGE_TYPE) | 84 | const type = peertubeLocalStorage.getItem(JobsComponent.LOCAL_STORAGE_TYPE) |
84 | if (type) this.jobType = type as JobType | 85 | if (type) this.jobType = type as JobType |
85 | } | 86 | } |
86 | 87 | ||
87 | private saveJobStateAndType () { | 88 | private saveJobStateAndType () { |
88 | peertubeLocalStorage.setItem(JobsComponent.JOB_STATE_LOCAL_STORAGE_STATE, this.jobState) | 89 | peertubeLocalStorage.setItem(JobsComponent.LOCAL_STORAGE_STATE, this.jobState) |
89 | peertubeLocalStorage.setItem(JobsComponent.JOB_STATE_LOCAL_STORAGE_TYPE, this.jobType) | 90 | peertubeLocalStorage.setItem(JobsComponent.LOCAL_STORAGE_TYPE, this.jobType) |
90 | } | 91 | } |
91 | } | 92 | } |
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 7479442d1..355cb4f55 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 | |||
@@ -9,7 +9,7 @@ export abstract class MyAccountVideoChannelEdit extends FormReactive { | |||
9 | abstract isCreation (): boolean | 9 | abstract isCreation (): boolean |
10 | abstract getFormButtonTitle (): string | 10 | abstract getFormButtonTitle (): string |
11 | 11 | ||
12 | // FIXME: We need this method so angular does not complain in the child template | 12 | // We need this method so angular does not complain in child template that doesn't need this |
13 | onAvatarChange (formData: FormData) { /* empty */ } | 13 | onAvatarChange (formData: FormData) { /* empty */ } |
14 | 14 | ||
15 | // Should be implemented by the child | 15 | // Should be implemented by the child |
diff --git a/client/src/app/+signup/+register/register-step-channel.component.html b/client/src/app/+signup/+register/register-step-channel.component.html index 88ff6e3ff..170c2964e 100644 --- a/client/src/app/+signup/+register/register-step-channel.component.html +++ b/client/src/app/+signup/+register/register-step-channel.component.html | |||
@@ -40,7 +40,7 @@ | |||
40 | </div> | 40 | </div> |
41 | 41 | ||
42 | <div class="name-information" i18n> | 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. | 43 | The channel name is a unique identifier of your channel on this and all the other instances. It's as unique as an email address, which makes it easy for other people to interact with it. |
44 | </div> | 44 | </div> |
45 | 45 | ||
46 | <div *ngIf="formErrors.name" class="form-error"> | 46 | <div *ngIf="formErrors.name" class="form-error"> |
diff --git a/client/src/app/+signup/+register/register-step-user.component.html b/client/src/app/+signup/+register/register-step-user.component.html index a2a657660..6bac4e4a4 100644 --- a/client/src/app/+signup/+register/register-step-user.component.html +++ b/client/src/app/+signup/+register/register-step-user.component.html | |||
@@ -29,7 +29,7 @@ | |||
29 | </div> | 29 | </div> |
30 | 30 | ||
31 | <div class="name-information" i18n> | 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. | 32 | The username is a unique identifier of your account on this and all the other instances. It's as unique as an email address, which makes it easy for other people to interact with it. |
33 | </div> | 33 | </div> |
34 | 34 | ||
35 | <div *ngIf="formErrors.username" class="form-error"> | 35 | <div *ngIf="formErrors.username" class="form-error"> |
diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index dda705811..62915ec54 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts | |||
@@ -48,8 +48,6 @@ export function metaFactory (serverService: ServerService): MetaLoader { | |||
48 | ], | 48 | ], |
49 | imports: [ | 49 | imports: [ |
50 | BrowserModule, | 50 | BrowserModule, |
51 | // FIXME: https://github.com/maxisam/ngx-clipboard/issues/133 | ||
52 | ClipboardModule, | ||
53 | 51 | ||
54 | CoreModule, | 52 | CoreModule, |
55 | SharedModule, | 53 | SharedModule, |
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index cdcbcb528..1f6cfb596 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts | |||
@@ -9,6 +9,7 @@ import { VideoConstant } from '../../../../../shared/models/videos' | |||
9 | import { isDefaultLocale, peertubeTranslate } from '../../../../../shared/models/i18n' | 9 | import { isDefaultLocale, peertubeTranslate } from '../../../../../shared/models/i18n' |
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 { ServerStats } from '@shared/models/server' | ||
12 | 13 | ||
13 | @Injectable() | 14 | @Injectable() |
14 | export class ServerService { | 15 | export class ServerService { |
@@ -16,6 +17,8 @@ export class ServerService { | |||
16 | private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/' | 17 | private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/' |
17 | private static BASE_VIDEO_PLAYLIST_URL = environment.apiUrl + '/api/v1/video-playlists/' | 18 | private static BASE_VIDEO_PLAYLIST_URL = environment.apiUrl + '/api/v1/video-playlists/' |
18 | private static BASE_LOCALE_URL = environment.apiUrl + '/client/locales/' | 19 | private static BASE_LOCALE_URL = environment.apiUrl + '/client/locales/' |
20 | private static BASE_STATS_URL = environment.apiUrl + '/api/v1/server/stats' | ||
21 | |||
19 | private static CONFIG_LOCAL_STORAGE_KEY = 'server-config' | 22 | private static CONFIG_LOCAL_STORAGE_KEY = 'server-config' |
20 | 23 | ||
21 | configReloaded = new Subject<void>() | 24 | configReloaded = new Subject<void>() |
@@ -235,6 +238,10 @@ export class ServerService { | |||
235 | return this.localeObservable.pipe(first()) | 238 | return this.localeObservable.pipe(first()) |
236 | } | 239 | } |
237 | 240 | ||
241 | getServerStats () { | ||
242 | return this.http.get<ServerStats>(ServerService.BASE_STATS_URL) | ||
243 | } | ||
244 | |||
238 | private loadAttributeEnum <T extends string | number> ( | 245 | private loadAttributeEnum <T extends string | number> ( |
239 | baseUrl: string, | 246 | baseUrl: string, |
240 | attributeName: 'categories' | 'licences' | 'languages' | 'privacies', | 247 | attributeName: 'categories' | 'licences' | 'languages' | 'privacies', |
diff --git a/client/src/app/search/search-filters.component.html b/client/src/app/search/search-filters.component.html index 07fb2c048..c275285d5 100644 --- a/client/src/app/search/search-filters.component.html +++ b/client/src/app/search/search-filters.component.html | |||
@@ -103,7 +103,7 @@ | |||
103 | </button> | 103 | </button> |
104 | <div class="peertube-select-container"> | 104 | <div class="peertube-select-container"> |
105 | <select id="category" name="category" [(ngModel)]="advancedSearch.categoryOneOf"> | 105 | <select id="category" name="category" [(ngModel)]="advancedSearch.categoryOneOf"> |
106 | <option [value]="undefined" i18n>Any or no category set</option> | 106 | <option [value]="undefined" i18n>Display all categories</option> |
107 | <option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option> | 107 | <option *ngFor="let category of videoCategories" [value]="category.id">{{ category.label }}</option> |
108 | </select> | 108 | </select> |
109 | </div> | 109 | </div> |
@@ -116,7 +116,7 @@ | |||
116 | </button> | 116 | </button> |
117 | <div class="peertube-select-container"> | 117 | <div class="peertube-select-container"> |
118 | <select id="licence" name="licence" [(ngModel)]="advancedSearch.licenceOneOf"> | 118 | <select id="licence" name="licence" [(ngModel)]="advancedSearch.licenceOneOf"> |
119 | <option [value]="undefined" i18n>Any or no license set</option> | 119 | <option [value]="undefined" i18n>Display all licenses</option> |
120 | <option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option> | 120 | <option *ngFor="let licence of videoLicences" [value]="licence.id">{{ licence.label }}</option> |
121 | </select> | 121 | </select> |
122 | </div> | 122 | </div> |
@@ -129,7 +129,7 @@ | |||
129 | </button> | 129 | </button> |
130 | <div class="peertube-select-container"> | 130 | <div class="peertube-select-container"> |
131 | <select id="language" name="language" [(ngModel)]="advancedSearch.languageOneOf"> | 131 | <select id="language" name="language" [(ngModel)]="advancedSearch.languageOneOf"> |
132 | <option [value]="undefined" i18n>Any or no language set</option> | 132 | <option [value]="undefined" i18n>Display all languages</option> |
133 | <option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option> | 133 | <option *ngFor="let language of videoLanguages" [value]="language.id">{{ language.label }}</option> |
134 | </select> | 134 | </select> |
135 | </div> | 135 | </div> |
diff --git a/client/src/app/shared/buttons/button.component.scss b/client/src/app/shared/buttons/button.component.scss index 2a8cfc748..3ccfefd7e 100644 --- a/client/src/app/shared/buttons/button.component.scss +++ b/client/src/app/shared/buttons/button.component.scss | |||
@@ -10,11 +10,26 @@ my-small-loader ::ng-deep .root { | |||
10 | .action-button { | 10 | .action-button { |
11 | @include peertube-button-link; | 11 | @include peertube-button-link; |
12 | @include button-with-icon(21px, 0, -2px); | 12 | @include button-with-icon(21px, 0, -2px); |
13 | } | ||
13 | 14 | ||
14 | // FIXME: Firefox does not apply global .orange-button icon color | 15 | .orange-button { |
15 | &.orange-button { | 16 | @include peertube-button; |
16 | @include apply-svg-color(#fff) | 17 | @include orange-button; |
17 | } | 18 | } |
19 | |||
20 | .orange-button-link { | ||
21 | @include peertube-button-link; | ||
22 | @include orange-button; | ||
23 | } | ||
24 | |||
25 | .grey-button { | ||
26 | @include peertube-button; | ||
27 | @include grey-button; | ||
28 | } | ||
29 | |||
30 | .grey-button-link { | ||
31 | @include peertube-button-link; | ||
32 | @include grey-button; | ||
18 | } | 33 | } |
19 | 34 | ||
20 | // In a table, try to minimize the space taken by this button | 35 | // In a table, try to minimize the space taken by this button |
diff --git a/client/src/app/shared/forms/form-validators/custom-config-validators.service.ts b/client/src/app/shared/forms/form-validators/custom-config-validators.service.ts index 767e3f026..d20754d11 100644 --- a/client/src/app/shared/forms/form-validators/custom-config-validators.service.ts +++ b/client/src/app/shared/forms/form-validators/custom-config-validators.service.ts | |||
@@ -56,7 +56,7 @@ export class CustomConfigValidatorsService { | |||
56 | } | 56 | } |
57 | 57 | ||
58 | this.SIGNUP_LIMIT = { | 58 | this.SIGNUP_LIMIT = { |
59 | VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ], | 59 | VALIDATORS: [ Validators.required, Validators.min(-1), Validators.pattern('-?[0-9]+') ], |
60 | MESSAGES: { | 60 | MESSAGES: { |
61 | 'required': this.i18n('Signup limit is required.'), | 61 | 'required': this.i18n('Signup limit is required.'), |
62 | 'min': this.i18n('Signup limit must be greater than 1.'), | 62 | 'min': this.i18n('Signup limit must be greater than 1.'), |
diff --git a/client/src/app/shared/images/global-icon.component.ts b/client/src/app/shared/images/global-icon.component.ts index 806aca347..b6e641228 100644 --- a/client/src/app/shared/images/global-icon.component.ts +++ b/client/src/app/shared/images/global-icon.component.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { ChangeDetectionStrategy, Component, ElementRef, Input, OnInit } from '@angular/core' | 1 | import { ChangeDetectionStrategy, Component, ElementRef, Input, OnInit } from '@angular/core' |
2 | import { HooksService } from '@app/core/plugins/hooks.service' | 2 | import { HooksService } from '@app/core/plugins/hooks.service' |
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
4 | 3 | ||
5 | const icons = { | 4 | const icons = { |
6 | 'add': require('!!raw-loader?!../../../assets/images/global/add.svg'), | 5 | 'add': require('!!raw-loader?!../../../assets/images/global/add.svg'), |
diff --git a/client/src/app/shared/instance/instance-statistics.component.ts b/client/src/app/shared/instance/instance-statistics.component.ts index 8ec728f05..40aa8a4c0 100644 --- a/client/src/app/shared/instance/instance-statistics.component.ts +++ b/client/src/app/shared/instance/instance-statistics.component.ts | |||
@@ -1,9 +1,6 @@ | |||
1 | import { map } from 'rxjs/operators' | ||
2 | import { HttpClient } from '@angular/common/http' | ||
3 | import { Component, OnInit } from '@angular/core' | 1 | import { Component, OnInit } from '@angular/core' |
4 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
5 | import { ServerStats } from '@shared/models/server' | 2 | import { ServerStats } from '@shared/models/server' |
6 | import { environment } from '../../../environments/environment' | 3 | import { ServerService } from '@app/core' |
7 | 4 | ||
8 | @Component({ | 5 | @Component({ |
9 | selector: 'my-instance-statistics', | 6 | selector: 'my-instance-statistics', |
@@ -11,27 +8,15 @@ import { environment } from '../../../environments/environment' | |||
11 | styleUrls: [ './instance-statistics.component.scss' ] | 8 | styleUrls: [ './instance-statistics.component.scss' ] |
12 | }) | 9 | }) |
13 | export class InstanceStatisticsComponent implements OnInit { | 10 | export class InstanceStatisticsComponent implements OnInit { |
14 | private static BASE_STATS_URL = environment.apiUrl + '/api/v1/server/stats' | ||
15 | |||
16 | serverStats: ServerStats = null | 11 | serverStats: ServerStats = null |
17 | 12 | ||
18 | constructor ( | 13 | constructor ( |
19 | private http: HttpClient, | 14 | private serverService: ServerService |
20 | private i18n: I18n | ||
21 | ) { | 15 | ) { |
22 | } | 16 | } |
23 | 17 | ||
24 | ngOnInit () { | 18 | ngOnInit () { |
25 | this.getStats() | 19 | this.serverService.getServerStats() |
26 | .subscribe( | 20 | .subscribe(res => this.serverStats = res) |
27 | res => { | ||
28 | this.serverStats = res | ||
29 | } | ||
30 | ) | ||
31 | } | ||
32 | |||
33 | getStats () { | ||
34 | return this.http | ||
35 | .get<ServerStats>(InstanceStatisticsComponent.BASE_STATS_URL) | ||
36 | } | 21 | } |
37 | } | 22 | } |
diff --git a/client/src/app/shared/menu/top-menu-dropdown.component.ts b/client/src/app/shared/menu/top-menu-dropdown.component.ts index 5ccdafb54..24a083654 100644 --- a/client/src/app/shared/menu/top-menu-dropdown.component.ts +++ b/client/src/app/shared/menu/top-menu-dropdown.component.ts | |||
@@ -49,8 +49,7 @@ export class TopMenuDropdownComponent implements OnInit, OnDestroy { | |||
49 | e => e.children && e.children.some(c => !!c.iconName) | 49 | e => e.children && e.children.some(c => !!c.iconName) |
50 | ) | 50 | ) |
51 | 51 | ||
52 | // FIXME: We have to set body for the container to avoid because of scroll overflow on mobile view | 52 | // We have to set body for the container to avoid scroll overflow on mobile view |
53 | // But this break our hovering system | ||
54 | if (this.screen.isInMobileView()) { | 53 | if (this.screen.isInMobileView()) { |
55 | this.container = 'body' | 54 | this.container = 'body' |
56 | } | 55 | } |
diff --git a/client/src/app/shared/renderer/markdown.service.ts b/client/src/app/shared/renderer/markdown.service.ts index 0d3fde537..f0c87326f 100644 --- a/client/src/app/shared/renderer/markdown.service.ts +++ b/client/src/app/shared/renderer/markdown.service.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Injectable } from '@angular/core' | 1 | import { Injectable } from '@angular/core' |
2 | import { MarkdownIt } from 'markdown-it' | ||
3 | import { buildVideoLink } from '../../../assets/player/utils' | 2 | import { buildVideoLink } from '../../../assets/player/utils' |
4 | import { HtmlRendererService } from '@app/shared/renderer/html-renderer.service' | 3 | import { HtmlRendererService } from '@app/shared/renderer/html-renderer.service' |
4 | import * as MarkdownIt from 'markdown-it' | ||
5 | 5 | ||
6 | type MarkdownParsers = { | 6 | type MarkdownParsers = { |
7 | textMarkdownIt: MarkdownIt | 7 | textMarkdownIt: MarkdownIt |
@@ -100,7 +100,7 @@ export class MarkdownService { | |||
100 | } | 100 | } |
101 | 101 | ||
102 | private async createMarkdownIt (config: MarkdownConfig) { | 102 | private async createMarkdownIt (config: MarkdownConfig) { |
103 | // FIXME: import('...') returns a struct module, containing a "default" field corresponding to our sanitizeHtml function | 103 | // FIXME: import('...') returns a struct module, containing a "default" field |
104 | const MarkdownItClass: typeof import ('markdown-it') = (await import('markdown-it') as any).default | 104 | const MarkdownItClass: typeof import ('markdown-it') = (await import('markdown-it') as any).default |
105 | 105 | ||
106 | const markdownIt = new MarkdownItClass('zero', { linkify: true, breaks: true, html: config.html }) | 106 | const markdownIt = new MarkdownItClass('zero', { linkify: true, breaks: true, html: config.html }) |
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index b2eb13f73..d06d37d8c 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts | |||
@@ -98,6 +98,7 @@ import { FollowService } from '@app/shared/instance/follow.service' | |||
98 | import { MultiSelectModule } from 'primeng/multiselect' | 98 | import { MultiSelectModule } from 'primeng/multiselect' |
99 | import { FeatureBooleanComponent } from '@app/shared/instance/feature-boolean.component' | 99 | import { FeatureBooleanComponent } from '@app/shared/instance/feature-boolean.component' |
100 | import { InputReadonlyCopyComponent } from '@app/shared/forms/input-readonly-copy.component' | 100 | import { InputReadonlyCopyComponent } from '@app/shared/forms/input-readonly-copy.component' |
101 | import { RedundancyService } from '@app/shared/video/redundancy.service' | ||
101 | 102 | ||
102 | @NgModule({ | 103 | @NgModule({ |
103 | imports: [ | 104 | imports: [ |
@@ -300,6 +301,7 @@ import { InputReadonlyCopyComponent } from '@app/shared/forms/input-readonly-cop | |||
300 | UserNotificationService, | 301 | UserNotificationService, |
301 | 302 | ||
302 | FollowService, | 303 | FollowService, |
304 | RedundancyService, | ||
303 | 305 | ||
304 | I18n | 306 | I18n |
305 | ] | 307 | ] |
diff --git a/client/src/app/shared/video/infinite-scroller.directive.ts b/client/src/app/shared/video/infinite-scroller.directive.ts index 9f613c5fa..f09c3d1fc 100644 --- a/client/src/app/shared/video/infinite-scroller.directive.ts +++ b/client/src/app/shared/video/infinite-scroller.directive.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { distinctUntilChanged, filter, map, share, startWith, tap, throttleTime } from 'rxjs/operators' | 1 | import { distinctUntilChanged, filter, map, share, startWith, throttleTime } from 'rxjs/operators' |
2 | import { AfterContentChecked, Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core' | 2 | import { AfterContentChecked, Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core' |
3 | import { fromEvent, Observable, Subscription } from 'rxjs' | 3 | import { fromEvent, Observable, Subscription } from 'rxjs' |
4 | 4 | ||
@@ -53,7 +53,7 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy, AfterConten | |||
53 | const scrollableElement = this.onItself ? this.container : window | 53 | const scrollableElement = this.onItself ? this.container : window |
54 | const scrollObservable = fromEvent(scrollableElement, 'scroll') | 54 | const scrollObservable = fromEvent(scrollableElement, 'scroll') |
55 | .pipe( | 55 | .pipe( |
56 | startWith(null as string), // FIXME: typings | 56 | startWith(true), |
57 | throttleTime(200, undefined, throttleOptions), | 57 | throttleTime(200, undefined, throttleOptions), |
58 | map(() => this.getScrollInfo()), | 58 | map(() => this.getScrollInfo()), |
59 | distinctUntilChanged((o1, o2) => o1.current === o2.current), | 59 | distinctUntilChanged((o1, o2) => o1.current === o2.current), |
diff --git a/client/src/app/shared/video/redundancy.service.ts b/client/src/app/shared/video/redundancy.service.ts new file mode 100644 index 000000000..fb918d73b --- /dev/null +++ b/client/src/app/shared/video/redundancy.service.ts | |||
@@ -0,0 +1,73 @@ | |||
1 | import { catchError, map, toArray } from 'rxjs/operators' | ||
2 | import { HttpClient, HttpParams } from '@angular/common/http' | ||
3 | import { Injectable } from '@angular/core' | ||
4 | import { RestExtractor, RestPagination, RestService } from '@app/shared/rest' | ||
5 | import { SortMeta } from 'primeng/api' | ||
6 | import { ResultList, Video, VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' | ||
7 | import { concat, Observable } from 'rxjs' | ||
8 | import { environment } from '../../../environments/environment' | ||
9 | |||
10 | @Injectable() | ||
11 | export class RedundancyService { | ||
12 | static BASE_REDUNDANCY_URL = environment.apiUrl + '/api/v1/server/redundancy' | ||
13 | |||
14 | constructor ( | ||
15 | private authHttp: HttpClient, | ||
16 | private restService: RestService, | ||
17 | private restExtractor: RestExtractor | ||
18 | ) { } | ||
19 | |||
20 | updateRedundancy (host: string, redundancyAllowed: boolean) { | ||
21 | const url = RedundancyService.BASE_REDUNDANCY_URL + '/' + host | ||
22 | |||
23 | const body = { redundancyAllowed } | ||
24 | |||
25 | return this.authHttp.put(url, body) | ||
26 | .pipe( | ||
27 | map(this.restExtractor.extractDataBool), | ||
28 | catchError(err => this.restExtractor.handleError(err)) | ||
29 | ) | ||
30 | } | ||
31 | |||
32 | listVideoRedundancies (options: { | ||
33 | pagination: RestPagination, | ||
34 | sort: SortMeta, | ||
35 | target?: VideoRedundanciesTarget | ||
36 | }): Observable<ResultList<VideoRedundancy>> { | ||
37 | const { pagination, sort, target } = options | ||
38 | |||
39 | let params = new HttpParams() | ||
40 | params = this.restService.addRestGetParams(params, pagination, sort) | ||
41 | |||
42 | if (target) params = params.append('target', target) | ||
43 | |||
44 | return this.authHttp.get<ResultList<VideoRedundancy>>(RedundancyService.BASE_REDUNDANCY_URL + '/videos', { params }) | ||
45 | .pipe( | ||
46 | catchError(res => this.restExtractor.handleError(res)) | ||
47 | ) | ||
48 | } | ||
49 | |||
50 | addVideoRedundancy (video: Video) { | ||
51 | return this.authHttp.post(RedundancyService.BASE_REDUNDANCY_URL + '/videos', { videoId: video.id }) | ||
52 | .pipe( | ||
53 | catchError(res => this.restExtractor.handleError(res)) | ||
54 | ) | ||
55 | } | ||
56 | |||
57 | removeVideoRedundancies (redundancy: VideoRedundancy) { | ||
58 | const observables = redundancy.redundancies.streamingPlaylists.map(r => r.id) | ||
59 | .concat(redundancy.redundancies.files.map(r => r.id)) | ||
60 | .map(id => this.removeRedundancy(id)) | ||
61 | |||
62 | return concat(...observables) | ||
63 | .pipe(toArray()) | ||
64 | } | ||
65 | |||
66 | private removeRedundancy (redundancyId: number) { | ||
67 | return this.authHttp.delete(RedundancyService.BASE_REDUNDANCY_URL + '/videos/' + redundancyId) | ||
68 | .pipe( | ||
69 | map(this.restExtractor.extractDataBool), | ||
70 | catchError(res => this.restExtractor.handleError(res)) | ||
71 | ) | ||
72 | } | ||
73 | } | ||
diff --git a/client/src/app/shared/video/video-actions-dropdown.component.ts b/client/src/app/shared/video/video-actions-dropdown.component.ts index afdeab18d..390d74c52 100644 --- a/client/src/app/shared/video/video-actions-dropdown.component.ts +++ b/client/src/app/shared/video/video-actions-dropdown.component.ts | |||
@@ -14,6 +14,7 @@ import { VideoBlacklistComponent } from '@app/shared/video/modals/video-blacklis | |||
14 | import { VideoBlacklistService } from '@app/shared/video-blacklist' | 14 | import { VideoBlacklistService } from '@app/shared/video-blacklist' |
15 | import { ScreenService } from '@app/shared/misc/screen.service' | 15 | import { ScreenService } from '@app/shared/misc/screen.service' |
16 | import { VideoCaption } from '@shared/models' | 16 | import { VideoCaption } from '@shared/models' |
17 | import { RedundancyService } from '@app/shared/video/redundancy.service' | ||
17 | 18 | ||
18 | export type VideoActionsDisplayType = { | 19 | export type VideoActionsDisplayType = { |
19 | playlist?: boolean | 20 | playlist?: boolean |
@@ -22,6 +23,7 @@ export type VideoActionsDisplayType = { | |||
22 | blacklist?: boolean | 23 | blacklist?: boolean |
23 | delete?: boolean | 24 | delete?: boolean |
24 | report?: boolean | 25 | report?: boolean |
26 | duplicate?: boolean | ||
25 | } | 27 | } |
26 | 28 | ||
27 | @Component({ | 29 | @Component({ |
@@ -46,7 +48,8 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
46 | update: true, | 48 | update: true, |
47 | blacklist: true, | 49 | blacklist: true, |
48 | delete: true, | 50 | delete: true, |
49 | report: true | 51 | report: true, |
52 | duplicate: true | ||
50 | } | 53 | } |
51 | @Input() placement = 'left' | 54 | @Input() placement = 'left' |
52 | 55 | ||
@@ -74,6 +77,7 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
74 | private screenService: ScreenService, | 77 | private screenService: ScreenService, |
75 | private videoService: VideoService, | 78 | private videoService: VideoService, |
76 | private blocklistService: BlocklistService, | 79 | private blocklistService: BlocklistService, |
80 | private redundancyService: RedundancyService, | ||
77 | private i18n: I18n | 81 | private i18n: I18n |
78 | ) { } | 82 | ) { } |
79 | 83 | ||
@@ -144,6 +148,10 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
144 | return this.video && this.video instanceof VideoDetails && this.video.downloadEnabled | 148 | return this.video && this.video instanceof VideoDetails && this.video.downloadEnabled |
145 | } | 149 | } |
146 | 150 | ||
151 | canVideoBeDuplicated () { | ||
152 | return this.video.canBeDuplicatedBy(this.user) | ||
153 | } | ||
154 | |||
147 | /* Action handlers */ | 155 | /* Action handlers */ |
148 | 156 | ||
149 | async unblacklistVideo () { | 157 | async unblacklistVideo () { |
@@ -186,6 +194,18 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
186 | ) | 194 | ) |
187 | } | 195 | } |
188 | 196 | ||
197 | duplicateVideo () { | ||
198 | this.redundancyService.addVideoRedundancy(this.video) | ||
199 | .subscribe( | ||
200 | () => { | ||
201 | const message = this.i18n('This video will be duplicated by your instance.') | ||
202 | this.notifier.success(message) | ||
203 | }, | ||
204 | |||
205 | err => this.notifier.error(err.message) | ||
206 | ) | ||
207 | } | ||
208 | |||
189 | onVideoBlacklisted () { | 209 | onVideoBlacklisted () { |
190 | this.videoBlacklisted.emit() | 210 | this.videoBlacklisted.emit() |
191 | } | 211 | } |
@@ -234,6 +254,12 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
234 | isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.blacklist && this.isVideoUnblacklistable() | 254 | isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.blacklist && this.isVideoUnblacklistable() |
235 | }, | 255 | }, |
236 | { | 256 | { |
257 | label: this.i18n('Duplicate (redundancy)'), | ||
258 | handler: () => this.duplicateVideo(), | ||
259 | isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.duplicate && this.canVideoBeDuplicated(), | ||
260 | iconName: 'cloud-download' | ||
261 | }, | ||
262 | { | ||
237 | label: this.i18n('Delete'), | 263 | label: this.i18n('Delete'), |
238 | handler: () => this.removeVideo(), | 264 | handler: () => this.removeVideo(), |
239 | isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.delete && this.isVideoRemovable(), | 265 | isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.delete && this.isVideoRemovable(), |
diff --git a/client/src/app/shared/video/video-miniature.component.html b/client/src/app/shared/video/video-miniature.component.html index 46c49c15b..819be6d48 100644 --- a/client/src/app/shared/video/video-miniature.component.html +++ b/client/src/app/shared/video/video-miniature.component.html | |||
@@ -50,7 +50,7 @@ | |||
50 | </div> | 50 | </div> |
51 | 51 | ||
52 | <div class="video-actions"> | 52 | <div class="video-actions"> |
53 | <!-- FIXME: remove bottom placement when overflow is fixed in bootstrap dropdown --> | 53 | <!-- FIXME: remove bottom placement when overflow is fixed in bootstrap dropdown: https://github.com/ng-bootstrap/ng-bootstrap/issues/3495 --> |
54 | <my-video-actions-dropdown | 54 | <my-video-actions-dropdown |
55 | *ngIf="showActions" [video]="video" [displayOptions]="videoActionsDisplayOptions" placement="bottom-left bottom-right left" | 55 | *ngIf="showActions" [video]="video" [displayOptions]="videoActionsDisplayOptions" placement="bottom-left bottom-right left" |
56 | (videoRemoved)="onVideoRemoved()" (videoBlacklisted)="onVideoBlacklisted()" (videoUnblacklisted)="onVideoUnblacklisted()" | 56 | (videoRemoved)="onVideoRemoved()" (videoBlacklisted)="onVideoBlacklisted()" (videoUnblacklisted)="onVideoUnblacklisted()" |
diff --git a/client/src/app/shared/video/video-miniature.component.ts b/client/src/app/shared/video/video-miniature.component.ts index 598a7a983..1dfb3eec7 100644 --- a/client/src/app/shared/video/video-miniature.component.ts +++ b/client/src/app/shared/video/video-miniature.component.ts | |||
@@ -64,7 +64,8 @@ export class VideoMiniatureComponent implements OnInit { | |||
64 | update: true, | 64 | update: true, |
65 | blacklist: true, | 65 | blacklist: true, |
66 | delete: true, | 66 | delete: true, |
67 | report: true | 67 | report: true, |
68 | duplicate: false | ||
68 | } | 69 | } |
69 | showActions = false | 70 | showActions = false |
70 | serverConfig: ServerConfig | 71 | serverConfig: ServerConfig |
diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts index fb98d5382..546518cca 100644 --- a/client/src/app/shared/video/video.model.ts +++ b/client/src/app/shared/video/video.model.ts | |||
@@ -42,6 +42,9 @@ export class Video implements VideoServerModel { | |||
42 | dislikes: number | 42 | dislikes: number |
43 | nsfw: boolean | 43 | nsfw: boolean |
44 | 44 | ||
45 | originInstanceUrl: string | ||
46 | originInstanceHost: string | ||
47 | |||
45 | waitTranscoding?: boolean | 48 | waitTranscoding?: boolean |
46 | state?: VideoConstant<VideoState> | 49 | state?: VideoConstant<VideoState> |
47 | scheduledUpdate?: VideoScheduleUpdate | 50 | scheduledUpdate?: VideoScheduleUpdate |
@@ -86,22 +89,31 @@ export class Video implements VideoServerModel { | |||
86 | this.waitTranscoding = hash.waitTranscoding | 89 | this.waitTranscoding = hash.waitTranscoding |
87 | this.state = hash.state | 90 | this.state = hash.state |
88 | this.description = hash.description | 91 | this.description = hash.description |
92 | |||
89 | this.duration = hash.duration | 93 | this.duration = hash.duration |
90 | this.durationLabel = durationToString(hash.duration) | 94 | this.durationLabel = durationToString(hash.duration) |
95 | |||
91 | this.id = hash.id | 96 | this.id = hash.id |
92 | this.uuid = hash.uuid | 97 | this.uuid = hash.uuid |
98 | |||
93 | this.isLocal = hash.isLocal | 99 | this.isLocal = hash.isLocal |
94 | this.name = hash.name | 100 | this.name = hash.name |
101 | |||
95 | this.thumbnailPath = hash.thumbnailPath | 102 | this.thumbnailPath = hash.thumbnailPath |
96 | this.thumbnailUrl = absoluteAPIUrl + hash.thumbnailPath | 103 | this.thumbnailUrl = absoluteAPIUrl + hash.thumbnailPath |
104 | |||
97 | this.previewPath = hash.previewPath | 105 | this.previewPath = hash.previewPath |
98 | this.previewUrl = absoluteAPIUrl + hash.previewPath | 106 | this.previewUrl = absoluteAPIUrl + hash.previewPath |
107 | |||
99 | this.embedPath = hash.embedPath | 108 | this.embedPath = hash.embedPath |
100 | this.embedUrl = absoluteAPIUrl + hash.embedPath | 109 | this.embedUrl = absoluteAPIUrl + hash.embedPath |
110 | |||
101 | this.views = hash.views | 111 | this.views = hash.views |
102 | this.likes = hash.likes | 112 | this.likes = hash.likes |
103 | this.dislikes = hash.dislikes | 113 | this.dislikes = hash.dislikes |
114 | |||
104 | this.nsfw = hash.nsfw | 115 | this.nsfw = hash.nsfw |
116 | |||
105 | this.account = hash.account | 117 | this.account = hash.account |
106 | this.channel = hash.channel | 118 | this.channel = hash.channel |
107 | 119 | ||
@@ -124,6 +136,9 @@ export class Video implements VideoServerModel { | |||
124 | this.blacklistedReason = hash.blacklistedReason | 136 | this.blacklistedReason = hash.blacklistedReason |
125 | 137 | ||
126 | this.userHistory = hash.userHistory | 138 | this.userHistory = hash.userHistory |
139 | |||
140 | this.originInstanceHost = this.account.host | ||
141 | this.originInstanceUrl = 'https://' + this.originInstanceHost | ||
127 | } | 142 | } |
128 | 143 | ||
129 | isVideoNSFWForUser (user: User, serverConfig: ServerConfig) { | 144 | isVideoNSFWForUser (user: User, serverConfig: ServerConfig) { |
@@ -152,4 +167,8 @@ export class Video implements VideoServerModel { | |||
152 | isUpdatableBy (user: AuthUser) { | 167 | isUpdatableBy (user: AuthUser) { |
153 | return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.UPDATE_ANY_VIDEO)) | 168 | return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.UPDATE_ANY_VIDEO)) |
154 | } | 169 | } |
170 | |||
171 | canBeDuplicatedBy (user: AuthUser) { | ||
172 | return user && this.isLocal === false && user.hasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES) | ||
173 | } | ||
155 | } | 174 | } |
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 bc3a3ffdd..a382777f5 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html | |||
@@ -188,6 +188,11 @@ | |||
188 | <span class="video-attribute-value">{{ video.privacy.label }}</span> | 188 | <span class="video-attribute-value">{{ video.privacy.label }}</span> |
189 | </div> | 189 | </div> |
190 | 190 | ||
191 | <div *ngIf="video.isLocal === false" class="video-attribute"> | ||
192 | <span i18n class="video-attribute-label">Origin instance</span> | ||
193 | <a class="video-attribute-value" target="_blank" rel="noopener noreferrer" [href]="video.originInstanceUrl">{{ video.originInstanceHost }}</a> | ||
194 | </div> | ||
195 | |||
191 | <div *ngIf="!!video.originallyPublishedAt" class="video-attribute"> | 196 | <div *ngIf="!!video.originallyPublishedAt" class="video-attribute"> |
192 | <span i18n class="video-attribute-label">Originally published</span> | 197 | <span i18n class="video-attribute-label">Originally published</span> |
193 | <span class="video-attribute-value">{{ video.originallyPublishedAt | date: 'dd MMMM yyyy' }}</span> | 198 | <span class="video-attribute-value">{{ video.originallyPublishedAt | date: 'dd MMMM yyyy' }}</span> |
diff --git a/client/src/assets/player/bezels/bezels-plugin.ts b/client/src/assets/player/bezels/bezels-plugin.ts index c2c251961..499177526 100644 --- a/client/src/assets/player/bezels/bezels-plugin.ts +++ b/client/src/assets/player/bezels/bezels-plugin.ts | |||
@@ -1,85 +1,12 @@ | |||
1 | // @ts-ignore | 1 | import videojs, { VideoJsPlayer } from 'video.js' |
2 | import * as videojs from 'video.js' | 2 | import './pause-bezel' |
3 | import { VideoJSComponentInterface } from '../peertube-videojs-typings' | ||
4 | 3 | ||
5 | function getPauseBezel () { | 4 | const Plugin = videojs.getPlugin('plugin') |
6 | return ` | ||
7 | <div class="vjs-bezels-pause"> | ||
8 | <div class="vjs-bezel" role="status" aria-label="Pause"> | ||
9 | <div class="vjs-bezel-icon"> | ||
10 | <svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%"> | ||
11 | <use class="vjs-svg-shadow" xlink:href="#vjs-id-1"></use> | ||
12 | <path class="vjs-svg-fill" d="M 12,26 16,26 16,10 12,10 z M 21,26 25,26 25,10 21,10 z" id="vjs-id-1"></path> | ||
13 | </svg> | ||
14 | </div> | ||
15 | </div> | ||
16 | </div> | ||
17 | ` | ||
18 | } | ||
19 | |||
20 | function getPlayBezel () { | ||
21 | return ` | ||
22 | <div class="vjs-bezels-play"> | ||
23 | <div class="vjs-bezel" role="status" aria-label="Play"> | ||
24 | <div class="vjs-bezel-icon"> | ||
25 | <svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%"> | ||
26 | <use class="vjs-svg-shadow" xlink:href="#vjs-id-2"></use> | ||
27 | <path class="vjs-svg-fill" d="M 12,26 18.5,22 18.5,14 12,10 z M 18.5,22 25,18 25,18 18.5,14 z" id="ytp-id-2"></path> | ||
28 | </svg> | ||
29 | </div> | ||
30 | </div> | ||
31 | </div> | ||
32 | ` | ||
33 | } | ||
34 | |||
35 | // @ts-ignore-start | ||
36 | const Component = videojs.getComponent('Component') | ||
37 | class PauseBezel extends Component { | ||
38 | options_: any | ||
39 | container: HTMLBodyElement | ||
40 | |||
41 | constructor (player: videojs.Player, options: any) { | ||
42 | super(player, options) | ||
43 | this.options_ = options | ||
44 | |||
45 | player.on('pause', (_: any) => { | ||
46 | if (player.seeking() || player.ended()) return | ||
47 | this.container.innerHTML = getPauseBezel() | ||
48 | this.showBezel() | ||
49 | }) | ||
50 | |||
51 | player.on('play', (_: any) => { | ||
52 | if (player.seeking()) return | ||
53 | this.container.innerHTML = getPlayBezel() | ||
54 | this.showBezel() | ||
55 | }) | ||
56 | } | ||
57 | 5 | ||
58 | createEl () { | ||
59 | const container = super.createEl('div', { | ||
60 | className: 'vjs-bezels-content' | ||
61 | }) | ||
62 | this.container = container | ||
63 | container.style.display = 'none' | ||
64 | |||
65 | return container | ||
66 | } | ||
67 | |||
68 | showBezel () { | ||
69 | this.container.style.display = 'inherit' | ||
70 | setTimeout(() => { | ||
71 | this.container.style.display = 'none' | ||
72 | }, 500) // matching the animation duration | ||
73 | } | ||
74 | } | ||
75 | // @ts-ignore-end | ||
76 | |||
77 | videojs.registerComponent('PauseBezel', PauseBezel) | ||
78 | |||
79 | const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') | ||
80 | class BezelsPlugin extends Plugin { | 6 | class BezelsPlugin extends Plugin { |
81 | constructor (player: videojs.Player, options: any = {}) { | 7 | |
82 | super(player, options) | 8 | constructor (player: VideoJsPlayer, options?: videojs.ComponentOptions) { |
9 | super(player) | ||
83 | 10 | ||
84 | this.player.ready(() => { | 11 | this.player.ready(() => { |
85 | player.addClass('vjs-bezels') | 12 | player.addClass('vjs-bezels') |
@@ -90,4 +17,5 @@ class BezelsPlugin extends Plugin { | |||
90 | } | 17 | } |
91 | 18 | ||
92 | videojs.registerPlugin('bezels', BezelsPlugin) | 19 | videojs.registerPlugin('bezels', BezelsPlugin) |
20 | |||
93 | export { BezelsPlugin } | 21 | export { BezelsPlugin } |
diff --git a/client/src/assets/player/bezels/pause-bezel.ts b/client/src/assets/player/bezels/pause-bezel.ts new file mode 100644 index 000000000..98eb12099 --- /dev/null +++ b/client/src/assets/player/bezels/pause-bezel.ts | |||
@@ -0,0 +1,72 @@ | |||
1 | import videojs, { VideoJsPlayer } from 'video.js' | ||
2 | |||
3 | function getPauseBezel () { | ||
4 | return ` | ||
5 | <div class="vjs-bezels-pause"> | ||
6 | <div class="vjs-bezel" role="status" aria-label="Pause"> | ||
7 | <div class="vjs-bezel-icon"> | ||
8 | <svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%"> | ||
9 | <use class="vjs-svg-shadow" xlink:href="#vjs-id-1"></use> | ||
10 | <path class="vjs-svg-fill" d="M 12,26 16,26 16,10 12,10 z M 21,26 25,26 25,10 21,10 z" id="vjs-id-1"></path> | ||
11 | </svg> | ||
12 | </div> | ||
13 | </div> | ||
14 | </div> | ||
15 | ` | ||
16 | } | ||
17 | |||
18 | function getPlayBezel () { | ||
19 | return ` | ||
20 | <div class="vjs-bezels-play"> | ||
21 | <div class="vjs-bezel" role="status" aria-label="Play"> | ||
22 | <div class="vjs-bezel-icon"> | ||
23 | <svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%"> | ||
24 | <use class="vjs-svg-shadow" xlink:href="#vjs-id-2"></use> | ||
25 | <path class="vjs-svg-fill" d="M 12,26 18.5,22 18.5,14 12,10 z M 18.5,22 25,18 25,18 18.5,14 z" id="ytp-id-2"></path> | ||
26 | </svg> | ||
27 | </div> | ||
28 | </div> | ||
29 | </div> | ||
30 | ` | ||
31 | } | ||
32 | |||
33 | const Component = videojs.getComponent('Component') | ||
34 | class PauseBezel extends Component { | ||
35 | container: HTMLDivElement | ||
36 | |||
37 | constructor (player: VideoJsPlayer, options?: videojs.ComponentOptions) { | ||
38 | super(player, options) | ||
39 | |||
40 | player.on('pause', (_: any) => { | ||
41 | if (player.seeking() || player.ended()) return | ||
42 | this.container.innerHTML = getPauseBezel() | ||
43 | this.showBezel() | ||
44 | }) | ||
45 | |||
46 | player.on('play', (_: any) => { | ||
47 | if (player.seeking()) return | ||
48 | this.container.innerHTML = getPlayBezel() | ||
49 | this.showBezel() | ||
50 | }) | ||
51 | } | ||
52 | |||
53 | createEl () { | ||
54 | this.container = super.createEl('div', { | ||
55 | className: 'vjs-bezels-content' | ||
56 | }) as HTMLDivElement | ||
57 | |||
58 | this.container.style.display = 'none' | ||
59 | |||
60 | return this.container | ||
61 | } | ||
62 | |||
63 | showBezel () { | ||
64 | this.container.style.display = 'inherit' | ||
65 | |||
66 | setTimeout(() => { | ||
67 | this.container.style.display = 'none' | ||
68 | }, 500) // matching the animation duration | ||
69 | } | ||
70 | } | ||
71 | |||
72 | videojs.registerComponent('PauseBezel', PauseBezel) | ||
diff --git a/client/src/assets/player/p2p-media-loader/hls-plugin.ts b/client/src/assets/player/p2p-media-loader/hls-plugin.ts new file mode 100644 index 000000000..d78e1ab90 --- /dev/null +++ b/client/src/assets/player/p2p-media-loader/hls-plugin.ts | |||
@@ -0,0 +1,626 @@ | |||
1 | // Thanks https://github.com/streamroot/videojs-hlsjs-plugin | ||
2 | // We duplicated this plugin to choose the hls.js version we want, because streamroot only provide a bundled file | ||
3 | |||
4 | import * as Hlsjs from 'hls.js' | ||
5 | import videojs, { VideoJsPlayer } from 'video.js' | ||
6 | import { HlsjsConfigHandlerOptions, QualityLevelRepresentation, QualityLevels, VideoJSTechHLS } from '../peertube-videojs-typings' | ||
7 | |||
8 | type ErrorCounts = { | ||
9 | [ type: string ]: number | ||
10 | } | ||
11 | |||
12 | type Metadata = { | ||
13 | levels: Hlsjs.Level[] | ||
14 | } | ||
15 | |||
16 | const registerSourceHandler = function (vjs: typeof videojs) { | ||
17 | if (!Hlsjs.isSupported()) { | ||
18 | console.warn('Hls.js is not supported in this browser!') | ||
19 | return | ||
20 | } | ||
21 | |||
22 | const html5 = vjs.getTech('Html5') | ||
23 | |||
24 | if (!html5) { | ||
25 | console.error('Not supported version if video.js') | ||
26 | return | ||
27 | } | ||
28 | |||
29 | // FIXME: typings | ||
30 | (html5 as any).registerSourceHandler({ | ||
31 | canHandleSource: function (source: videojs.Tech.SourceObject) { | ||
32 | const hlsTypeRE = /^application\/x-mpegURL|application\/vnd\.apple\.mpegurl$/i | ||
33 | const hlsExtRE = /\.m3u8/i | ||
34 | |||
35 | if (hlsTypeRE.test(source.type)) return 'probably' | ||
36 | if (hlsExtRE.test(source.src)) return 'maybe' | ||
37 | |||
38 | return '' | ||
39 | }, | ||
40 | |||
41 | handleSource: function (source: videojs.Tech.SourceObject, tech: VideoJSTechHLS) { | ||
42 | if (tech.hlsProvider) { | ||
43 | tech.hlsProvider.dispose() | ||
44 | } | ||
45 | |||
46 | tech.hlsProvider = new Html5Hlsjs(vjs, source, tech) | ||
47 | |||
48 | return tech.hlsProvider | ||
49 | } | ||
50 | }, 0); | ||
51 | |||
52 | // FIXME: typings | ||
53 | (vjs as any).Html5Hlsjs = Html5Hlsjs | ||
54 | } | ||
55 | |||
56 | function hlsjsConfigHandler (this: VideoJsPlayer, options: HlsjsConfigHandlerOptions) { | ||
57 | const player = this | ||
58 | |||
59 | if (!options) return | ||
60 | |||
61 | if (!player.srOptions_) { | ||
62 | player.srOptions_ = {} | ||
63 | } | ||
64 | |||
65 | if (!player.srOptions_.hlsjsConfig) { | ||
66 | player.srOptions_.hlsjsConfig = options.hlsjsConfig | ||
67 | } | ||
68 | |||
69 | if (!player.srOptions_.captionConfig) { | ||
70 | player.srOptions_.captionConfig = options.captionConfig | ||
71 | } | ||
72 | |||
73 | if (options.levelLabelHandler && !player.srOptions_.levelLabelHandler) { | ||
74 | player.srOptions_.levelLabelHandler = options.levelLabelHandler | ||
75 | } | ||
76 | } | ||
77 | |||
78 | const registerConfigPlugin = function (vjs: typeof videojs) { | ||
79 | // Used in Brightcove since we don't pass options directly there | ||
80 | const registerVjsPlugin = vjs.registerPlugin || vjs.plugin | ||
81 | registerVjsPlugin('hlsjs', hlsjsConfigHandler) | ||
82 | } | ||
83 | |||
84 | class Html5Hlsjs { | ||
85 | private static readonly hooks: { [id: string]: Function[] } = {} | ||
86 | |||
87 | private readonly videoElement: HTMLVideoElement | ||
88 | private readonly errorCounts: ErrorCounts = {} | ||
89 | private readonly player: VideoJsPlayer | ||
90 | private readonly tech: videojs.Tech | ||
91 | private readonly source: videojs.Tech.SourceObject | ||
92 | private readonly vjs: typeof videojs | ||
93 | |||
94 | private hls: Hlsjs & { manualLevel?: number } // FIXME: typings | ||
95 | private hlsjsConfig: Partial<Hlsjs.Config & { cueHandler: any }> = null | ||
96 | |||
97 | private _duration: number = null | ||
98 | private metadata: Metadata = null | ||
99 | private isLive: boolean = null | ||
100 | private dvrDuration: number = null | ||
101 | private edgeMargin: number = null | ||
102 | |||
103 | private handlers: { [ id in 'play' | 'addtrack' | 'playing' | 'textTracksChange' | 'audioTracksChange' ]: EventListener } = { | ||
104 | play: null, | ||
105 | addtrack: null, | ||
106 | playing: null, | ||
107 | textTracksChange: null, | ||
108 | audioTracksChange: null | ||
109 | } | ||
110 | |||
111 | private uiTextTrackHandled = false | ||
112 | |||
113 | constructor (vjs: typeof videojs, source: videojs.Tech.SourceObject, tech: videojs.Tech) { | ||
114 | this.vjs = vjs | ||
115 | this.source = source | ||
116 | |||
117 | this.tech = tech; | ||
118 | (this.tech as any).name_ = 'Hlsjs' | ||
119 | |||
120 | this.videoElement = tech.el() as HTMLVideoElement | ||
121 | this.player = vjs((tech.options_ as any).playerId) | ||
122 | |||
123 | this.videoElement.addEventListener('error', event => { | ||
124 | let errorTxt: string | ||
125 | const mediaError = (event.currentTarget as HTMLVideoElement).error | ||
126 | |||
127 | switch (mediaError.code) { | ||
128 | case mediaError.MEDIA_ERR_ABORTED: | ||
129 | errorTxt = 'You aborted the video playback' | ||
130 | break | ||
131 | case mediaError.MEDIA_ERR_DECODE: | ||
132 | errorTxt = 'The video playback was aborted due to a corruption problem or because the video used features your browser did not support' | ||
133 | this._handleMediaError(mediaError) | ||
134 | break | ||
135 | case mediaError.MEDIA_ERR_NETWORK: | ||
136 | errorTxt = 'A network error caused the video download to fail part-way' | ||
137 | break | ||
138 | case mediaError.MEDIA_ERR_SRC_NOT_SUPPORTED: | ||
139 | errorTxt = 'The video could not be loaded, either because the server or network failed or because the format is not supported' | ||
140 | break | ||
141 | |||
142 | default: | ||
143 | errorTxt = mediaError.message | ||
144 | } | ||
145 | |||
146 | console.error('MEDIA_ERROR: ', errorTxt) | ||
147 | }) | ||
148 | |||
149 | this.initialize() | ||
150 | } | ||
151 | |||
152 | duration () { | ||
153 | return this._duration || this.videoElement.duration || 0 | ||
154 | } | ||
155 | |||
156 | seekable () { | ||
157 | if (this.hls.media) { | ||
158 | if (!this.isLive) { | ||
159 | return this.vjs.createTimeRanges(0, this.hls.media.duration) | ||
160 | } | ||
161 | |||
162 | // Video.js doesn't seem to like floating point timeranges | ||
163 | const startTime = Math.round(this.hls.media.duration - this.dvrDuration) | ||
164 | const endTime = Math.round(this.hls.media.duration - this.edgeMargin) | ||
165 | |||
166 | return this.vjs.createTimeRanges(startTime, endTime) | ||
167 | } | ||
168 | |||
169 | return this.vjs.createTimeRanges() | ||
170 | } | ||
171 | |||
172 | // See comment for `initialize` method. | ||
173 | dispose () { | ||
174 | this.videoElement.removeEventListener('play', this.handlers.play) | ||
175 | this.videoElement.textTracks.removeEventListener('addtrack', this.handlers.addtrack) | ||
176 | this.videoElement.removeEventListener('playing', this.handlers.playing) | ||
177 | |||
178 | this.player.textTracks().removeEventListener('change', this.handlers.textTracksChange) | ||
179 | this.uiTextTrackHandled = false | ||
180 | |||
181 | this.player.audioTracks().removeEventListener('change', this.handlers.audioTracksChange) | ||
182 | |||
183 | this.hls.destroy() | ||
184 | } | ||
185 | |||
186 | static addHook (type: string, callback: Function) { | ||
187 | Html5Hlsjs.hooks[ type ] = this.hooks[ type ] || [] | ||
188 | Html5Hlsjs.hooks[ type ].push(callback) | ||
189 | } | ||
190 | |||
191 | static removeHook (type: string, callback: Function) { | ||
192 | if (Html5Hlsjs.hooks[ type ] === undefined) return false | ||
193 | |||
194 | const index = Html5Hlsjs.hooks[ type ].indexOf(callback) | ||
195 | if (index === -1) return false | ||
196 | |||
197 | Html5Hlsjs.hooks[ type ].splice(index, 1) | ||
198 | |||
199 | return true | ||
200 | } | ||
201 | |||
202 | private _executeHooksFor (type: string) { | ||
203 | if (Html5Hlsjs.hooks[ type ] === undefined) { | ||
204 | return | ||
205 | } | ||
206 | |||
207 | // ES3 and IE < 9 | ||
208 | for (let i = 0; i < Html5Hlsjs.hooks[ type ].length; i++) { | ||
209 | Html5Hlsjs.hooks[ type ][ i ](this.player, this.hls) | ||
210 | } | ||
211 | } | ||
212 | |||
213 | private _handleMediaError (error: any) { | ||
214 | if (this.errorCounts[ Hlsjs.ErrorTypes.MEDIA_ERROR ] === 1) { | ||
215 | console.info('trying to recover media error') | ||
216 | this.hls.recoverMediaError() | ||
217 | return | ||
218 | } | ||
219 | |||
220 | if (this.errorCounts[ Hlsjs.ErrorTypes.MEDIA_ERROR ] === 2) { | ||
221 | console.info('2nd try to recover media error (by swapping audio codec') | ||
222 | this.hls.swapAudioCodec() | ||
223 | this.hls.recoverMediaError() | ||
224 | return | ||
225 | } | ||
226 | |||
227 | if (this.errorCounts[ Hlsjs.ErrorTypes.MEDIA_ERROR ] > 2) { | ||
228 | console.info('bubbling media error up to VIDEOJS') | ||
229 | this.tech.error = () => error | ||
230 | this.tech.trigger('error') | ||
231 | return | ||
232 | } | ||
233 | } | ||
234 | |||
235 | private _onError (_event: any, data: Hlsjs.errorData) { | ||
236 | const error: { message: string, code?: number } = { | ||
237 | message: `HLS.js error: ${data.type} - fatal: ${data.fatal} - ${data.details}` | ||
238 | } | ||
239 | console.error(error.message) | ||
240 | |||
241 | // increment/set error count | ||
242 | if (this.errorCounts[ data.type ]) this.errorCounts[ data.type ] += 1 | ||
243 | else this.errorCounts[ data.type ] = 1 | ||
244 | |||
245 | // Implement simple error handling based on hls.js documentation | ||
246 | // https://github.com/dailymotion/hls.js/blob/master/API.md#fifth-step-error-handling | ||
247 | if (data.fatal) { | ||
248 | switch (data.type) { | ||
249 | case Hlsjs.ErrorTypes.NETWORK_ERROR: | ||
250 | console.info('bubbling network error up to VIDEOJS') | ||
251 | error.code = 2 | ||
252 | this.tech.error = () => error as any | ||
253 | this.tech.trigger('error') | ||
254 | break | ||
255 | |||
256 | case Hlsjs.ErrorTypes.MEDIA_ERROR: | ||
257 | error.code = 3 | ||
258 | this._handleMediaError(error) | ||
259 | break | ||
260 | |||
261 | default: | ||
262 | // cannot recover | ||
263 | this.hls.destroy() | ||
264 | console.info('bubbling error up to VIDEOJS') | ||
265 | this.tech.error = () => error as any | ||
266 | this.tech.trigger('error') | ||
267 | break | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | private switchQuality (qualityId: number) { | ||
273 | this.hls.nextLevel = qualityId | ||
274 | } | ||
275 | |||
276 | private _levelLabel (level: Hlsjs.Level) { | ||
277 | if (this.player.srOptions_.levelLabelHandler) { | ||
278 | return this.player.srOptions_.levelLabelHandler(level) | ||
279 | } | ||
280 | |||
281 | if (level.height) return level.height + 'p' | ||
282 | if (level.width) return Math.round(level.width * 9 / 16) + 'p' | ||
283 | if (level.bitrate) return (level.bitrate / 1000) + 'kbps' | ||
284 | |||
285 | return 0 | ||
286 | } | ||
287 | |||
288 | private _relayQualityChange (qualityLevels: QualityLevels) { | ||
289 | // Determine if it is "Auto" (all tracks enabled) | ||
290 | let isAuto = true | ||
291 | |||
292 | for (let i = 0; i < qualityLevels.length; i++) { | ||
293 | if (!qualityLevels[ i ]._enabled) { | ||
294 | isAuto = false | ||
295 | break | ||
296 | } | ||
297 | } | ||
298 | |||
299 | // Interact with ME | ||
300 | if (isAuto) { | ||
301 | this.hls.currentLevel = -1 | ||
302 | return | ||
303 | } | ||
304 | |||
305 | // Find ID of highest enabled track | ||
306 | let selectedTrack: number | ||
307 | |||
308 | for (selectedTrack = qualityLevels.length - 1; selectedTrack >= 0; selectedTrack--) { | ||
309 | if (qualityLevels[ selectedTrack ]._enabled) { | ||
310 | break | ||
311 | } | ||
312 | } | ||
313 | |||
314 | this.hls.currentLevel = selectedTrack | ||
315 | } | ||
316 | |||
317 | private _handleQualityLevels () { | ||
318 | if (!this.metadata) return | ||
319 | |||
320 | const qualityLevels = this.player.qualityLevels && this.player.qualityLevels() | ||
321 | if (!qualityLevels) return | ||
322 | |||
323 | for (let i = 0; i < this.metadata.levels.length; i++) { | ||
324 | const details = this.metadata.levels[ i ] | ||
325 | const representation: QualityLevelRepresentation = { | ||
326 | id: i, | ||
327 | width: details.width, | ||
328 | height: details.height, | ||
329 | bandwidth: details.bitrate, | ||
330 | bitrate: details.bitrate, | ||
331 | _enabled: true | ||
332 | } | ||
333 | |||
334 | const self = this | ||
335 | representation.enabled = function (this: QualityLevels, level: number, toggle?: boolean) { | ||
336 | // Brightcove switcher works TextTracks-style (enable tracks that it wants to ABR on) | ||
337 | if (typeof toggle === 'boolean') { | ||
338 | this[ level ]._enabled = toggle | ||
339 | self._relayQualityChange(this) | ||
340 | } | ||
341 | |||
342 | return this[ level ]._enabled | ||
343 | } | ||
344 | |||
345 | qualityLevels.addQualityLevel(representation) | ||
346 | } | ||
347 | } | ||
348 | |||
349 | private _notifyVideoQualities () { | ||
350 | if (!this.metadata) return | ||
351 | const cleanTracklist = [] | ||
352 | |||
353 | if (this.metadata.levels.length > 1) { | ||
354 | const autoLevel = { | ||
355 | id: -1, | ||
356 | label: 'auto', | ||
357 | selected: this.hls.manualLevel === -1 | ||
358 | } | ||
359 | cleanTracklist.push(autoLevel) | ||
360 | } | ||
361 | |||
362 | this.metadata.levels.forEach((level, index) => { | ||
363 | // Don't write in level (shared reference with Hls.js) | ||
364 | const quality = { | ||
365 | id: index, | ||
366 | selected: index === this.hls.manualLevel, | ||
367 | label: this._levelLabel(level) | ||
368 | } | ||
369 | |||
370 | cleanTracklist.push(quality) | ||
371 | }) | ||
372 | |||
373 | const payload = { | ||
374 | qualityData: { video: cleanTracklist }, | ||
375 | qualitySwitchCallback: this.switchQuality.bind(this) | ||
376 | } | ||
377 | |||
378 | this.tech.trigger('loadedqualitydata', payload) | ||
379 | |||
380 | // Self-de-register so we don't raise the payload multiple times | ||
381 | this.videoElement.removeEventListener('playing', this.handlers.playing) | ||
382 | } | ||
383 | |||
384 | private _updateSelectedAudioTrack () { | ||
385 | const playerAudioTracks = this.tech.audioTracks() | ||
386 | for (let j = 0; j < playerAudioTracks.length; j++) { | ||
387 | // FIXME: typings | ||
388 | if ((playerAudioTracks[ j ] as any).enabled) { | ||
389 | this.hls.audioTrack = j | ||
390 | break | ||
391 | } | ||
392 | } | ||
393 | } | ||
394 | |||
395 | private _onAudioTracks () { | ||
396 | const hlsAudioTracks = this.hls.audioTracks as (AudioTrack & { name?: string, lang?: string })[] // FIXME typings | ||
397 | const playerAudioTracks = this.tech.audioTracks() | ||
398 | |||
399 | if (hlsAudioTracks.length > 1 && playerAudioTracks.length === 0) { | ||
400 | // Add Hls.js audio tracks if not added yet | ||
401 | for (let i = 0; i < hlsAudioTracks.length; i++) { | ||
402 | playerAudioTracks.addTrack(new this.vjs.AudioTrack({ | ||
403 | id: i.toString(), | ||
404 | kind: 'alternative', | ||
405 | label: hlsAudioTracks[ i ].name || hlsAudioTracks[ i ].lang, | ||
406 | language: hlsAudioTracks[ i ].lang, | ||
407 | enabled: i === this.hls.audioTrack | ||
408 | })) | ||
409 | } | ||
410 | |||
411 | // Handle audio track change event | ||
412 | this.handlers.audioTracksChange = this._updateSelectedAudioTrack.bind(this) | ||
413 | playerAudioTracks.addEventListener('change', this.handlers.audioTracksChange) | ||
414 | } | ||
415 | } | ||
416 | |||
417 | private _getTextTrackLabel (textTrack: TextTrack) { | ||
418 | // Label here is readable label and is optional (used in the UI so if it is there it should be different) | ||
419 | return textTrack.label ? textTrack.label : textTrack.language | ||
420 | } | ||
421 | |||
422 | private _isSameTextTrack (track1: TextTrack, track2: TextTrack) { | ||
423 | return this._getTextTrackLabel(track1) === this._getTextTrackLabel(track2) | ||
424 | && track1.kind === track2.kind | ||
425 | } | ||
426 | |||
427 | private _updateSelectedTextTrack () { | ||
428 | const playerTextTracks = this.player.textTracks() | ||
429 | let activeTrack: TextTrack = null | ||
430 | |||
431 | for (let j = 0; j < playerTextTracks.length; j++) { | ||
432 | if (playerTextTracks[ j ].mode === 'showing') { | ||
433 | activeTrack = playerTextTracks[ j ] | ||
434 | break | ||
435 | } | ||
436 | } | ||
437 | |||
438 | const hlsjsTracks = this.videoElement.textTracks | ||
439 | for (let k = 0; k < hlsjsTracks.length; k++) { | ||
440 | if (hlsjsTracks[ k ].kind === 'subtitles' || hlsjsTracks[ k ].kind === 'captions') { | ||
441 | hlsjsTracks[ k ].mode = activeTrack && this._isSameTextTrack(hlsjsTracks[ k ], activeTrack) | ||
442 | ? 'showing' | ||
443 | : 'disabled' | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | |||
448 | private _startLoad () { | ||
449 | this.hls.startLoad(-1) | ||
450 | this.videoElement.removeEventListener('play', this.handlers.play) | ||
451 | } | ||
452 | |||
453 | private _oneLevelObjClone (obj: object) { | ||
454 | const result = {} | ||
455 | const objKeys = Object.keys(obj) | ||
456 | for (let i = 0; i < objKeys.length; i++) { | ||
457 | result[ objKeys[ i ] ] = obj[ objKeys[ i ] ] | ||
458 | } | ||
459 | |||
460 | return result | ||
461 | } | ||
462 | |||
463 | private _filterDisplayableTextTracks (textTracks: TextTrackList) { | ||
464 | const displayableTracks = [] | ||
465 | |||
466 | // Filter out tracks that is displayable (captions or subtitles) | ||
467 | for (let idx = 0; idx < textTracks.length; idx++) { | ||
468 | if (textTracks[ idx ].kind === 'subtitles' || textTracks[ idx ].kind === 'captions') { | ||
469 | displayableTracks.push(textTracks[ idx ]) | ||
470 | } | ||
471 | } | ||
472 | |||
473 | return displayableTracks | ||
474 | } | ||
475 | |||
476 | private _updateTextTrackList () { | ||
477 | const displayableTracks = this._filterDisplayableTextTracks(this.videoElement.textTracks) | ||
478 | const playerTextTracks = this.player.textTracks() | ||
479 | |||
480 | // Add stubs to make the caption switcher shows up | ||
481 | // Adding the Hls.js text track in will make us have double captions | ||
482 | for (let idx = 0; idx < displayableTracks.length; idx++) { | ||
483 | let isAdded = false | ||
484 | |||
485 | for (let jdx = 0; jdx < playerTextTracks.length; jdx++) { | ||
486 | if (this._isSameTextTrack(displayableTracks[ idx ], playerTextTracks[ jdx ])) { | ||
487 | isAdded = true | ||
488 | break | ||
489 | } | ||
490 | } | ||
491 | |||
492 | if (!isAdded) { | ||
493 | const hlsjsTextTrack = displayableTracks[ idx ] | ||
494 | this.player.addRemoteTextTrack({ | ||
495 | kind: hlsjsTextTrack.kind as videojs.TextTrack.Kind, | ||
496 | label: this._getTextTrackLabel(hlsjsTextTrack), | ||
497 | language: hlsjsTextTrack.language, | ||
498 | srclang: hlsjsTextTrack.language | ||
499 | }, false) | ||
500 | } | ||
501 | } | ||
502 | |||
503 | // Handle UI switching | ||
504 | this._updateSelectedTextTrack() | ||
505 | |||
506 | if (!this.uiTextTrackHandled) { | ||
507 | this.handlers.textTracksChange = this._updateSelectedTextTrack.bind(this) | ||
508 | playerTextTracks.addEventListener('change', this.handlers.textTracksChange) | ||
509 | |||
510 | this.uiTextTrackHandled = true | ||
511 | } | ||
512 | } | ||
513 | |||
514 | private _onMetaData (_event: any, data: Hlsjs.manifestLoadedData) { | ||
515 | // This could arrive before 'loadedqualitydata' handlers is registered, remember it so we can raise it later | ||
516 | this.metadata = data as any | ||
517 | this._handleQualityLevels() | ||
518 | } | ||
519 | |||
520 | private _createCueHandler (captionConfig: any) { | ||
521 | return { | ||
522 | newCue: (track: any, startTime: number, endTime: number, captionScreen: { rows: any[] }) => { | ||
523 | let row: any | ||
524 | let cue: VTTCue | ||
525 | let text: string | ||
526 | const VTTCue = (window as any).VTTCue || (window as any).TextTrackCue | ||
527 | |||
528 | for (let r = 0; r < captionScreen.rows.length; r++) { | ||
529 | row = captionScreen.rows[ r ] | ||
530 | text = '' | ||
531 | |||
532 | if (!row.isEmpty()) { | ||
533 | for (let c = 0; c < row.chars.length; c++) { | ||
534 | text += row.chars[ c ].ucharj | ||
535 | } | ||
536 | |||
537 | cue = new VTTCue(startTime, endTime, text.trim()) | ||
538 | |||
539 | // typeof null === 'object' | ||
540 | if (captionConfig != null && typeof captionConfig === 'object') { | ||
541 | // Copy client overridden property into the cue object | ||
542 | const configKeys = Object.keys(captionConfig) | ||
543 | |||
544 | for (let k = 0; k < configKeys.length; k++) { | ||
545 | cue[ configKeys[ k ] ] = captionConfig[ configKeys[ k ] ] | ||
546 | } | ||
547 | } | ||
548 | track.addCue(cue) | ||
549 | if (endTime === startTime) track.addCue(new VTTCue(endTime + 5, '')) | ||
550 | } | ||
551 | } | ||
552 | } | ||
553 | } | ||
554 | } | ||
555 | |||
556 | private _initHlsjs () { | ||
557 | const techOptions = this.tech.options_ as HlsjsConfigHandlerOptions | ||
558 | const srOptions_ = this.player.srOptions_ | ||
559 | |||
560 | const hlsjsConfigRef = srOptions_ && srOptions_.hlsjsConfig || techOptions.hlsjsConfig | ||
561 | // Hls.js will write to the reference thus change the object for later streams | ||
562 | this.hlsjsConfig = hlsjsConfigRef ? this._oneLevelObjClone(hlsjsConfigRef) : {} | ||
563 | |||
564 | if ([ '', 'auto' ].includes(this.videoElement.preload) && !this.videoElement.autoplay && this.hlsjsConfig.autoStartLoad === undefined) { | ||
565 | this.hlsjsConfig.autoStartLoad = false | ||
566 | } | ||
567 | |||
568 | const captionConfig = srOptions_ && srOptions_.captionConfig || techOptions.captionConfig | ||
569 | if (captionConfig) { | ||
570 | this.hlsjsConfig.cueHandler = this._createCueHandler(captionConfig) | ||
571 | } | ||
572 | |||
573 | // If the user explicitly sets autoStartLoad to false, we're not going to enter the if block above | ||
574 | // That's why we have a separate if block here to set the 'play' listener | ||
575 | if (this.hlsjsConfig.autoStartLoad === false) { | ||
576 | this.handlers.play = this._startLoad.bind(this) | ||
577 | this.videoElement.addEventListener('play', this.handlers.play) | ||
578 | } | ||
579 | |||
580 | // _notifyVideoQualities sometimes runs before the quality picker event handler is registered -> no video switcher | ||
581 | this.handlers.playing = this._notifyVideoQualities.bind(this) | ||
582 | this.videoElement.addEventListener('playing', this.handlers.playing) | ||
583 | |||
584 | this.hls = new Hlsjs(this.hlsjsConfig) | ||
585 | |||
586 | this._executeHooksFor('beforeinitialize') | ||
587 | |||
588 | this.hls.on(Hlsjs.Events.ERROR, (event, data) => this._onError(event, data)) | ||
589 | this.hls.on(Hlsjs.Events.AUDIO_TRACKS_UPDATED, () => this._onAudioTracks()) | ||
590 | this.hls.on(Hlsjs.Events.MANIFEST_PARSED, (event, data) => this._onMetaData(event, data as any)) // FIXME: typings | ||
591 | this.hls.on(Hlsjs.Events.LEVEL_LOADED, (event, data) => { | ||
592 | // The DVR plugin will auto seek to "live edge" on start up | ||
593 | if (this.hlsjsConfig.liveSyncDuration) { | ||
594 | this.edgeMargin = this.hlsjsConfig.liveSyncDuration | ||
595 | } else if (this.hlsjsConfig.liveSyncDurationCount) { | ||
596 | this.edgeMargin = this.hlsjsConfig.liveSyncDurationCount * data.details.targetduration | ||
597 | } | ||
598 | |||
599 | this.isLive = data.details.live | ||
600 | this.dvrDuration = data.details.totalduration | ||
601 | this._duration = this.isLive ? Infinity : data.details.totalduration | ||
602 | }) | ||
603 | this.hls.once(Hlsjs.Events.FRAG_LOADED, () => { | ||
604 | // Emit custom 'loadedmetadata' event for parity with `videojs-contrib-hls` | ||
605 | // Ref: https://github.com/videojs/videojs-contrib-hls#loadedmetadata | ||
606 | this.tech.trigger('loadedmetadata') | ||
607 | }) | ||
608 | |||
609 | this.hls.attachMedia(this.videoElement) | ||
610 | |||
611 | this.handlers.addtrack = this._updateTextTrackList.bind(this) | ||
612 | this.videoElement.textTracks.addEventListener('addtrack', this.handlers.addtrack) | ||
613 | |||
614 | this.hls.loadSource(this.source.src) | ||
615 | } | ||
616 | |||
617 | private initialize () { | ||
618 | this._initHlsjs() | ||
619 | } | ||
620 | } | ||
621 | |||
622 | export { | ||
623 | Html5Hlsjs, | ||
624 | registerSourceHandler, | ||
625 | registerConfigPlugin | ||
626 | } | ||
diff --git a/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts b/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts index c3f863f72..e86900faa 100644 --- a/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts +++ b/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts | |||
@@ -1,16 +1,15 @@ | |||
1 | // FIXME: something weird with our path definition in tsconfig and typings | 1 | import videojs, { VideoJsPlayer } from 'video.js' |
2 | // @ts-ignore | 2 | import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo } from '../peertube-videojs-typings' |
3 | import * as videojs from 'video.js' | ||
4 | import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo, VideoJSComponentInterface } from '../peertube-videojs-typings' | ||
5 | import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from 'p2p-media-loader-hlsjs' | 3 | import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from 'p2p-media-loader-hlsjs' |
6 | import { Events, Segment } from 'p2p-media-loader-core' | 4 | import { Events, Segment } from 'p2p-media-loader-core' |
7 | import { timeToInt } from '../utils' | 5 | import { timeToInt } from '../utils' |
6 | import { registerConfigPlugin, registerSourceHandler } from './hls-plugin' | ||
7 | import * as Hlsjs from 'hls.js' | ||
8 | 8 | ||
9 | // videojs-hlsjs-plugin needs videojs in window | 9 | registerConfigPlugin(videojs) |
10 | window['videojs'] = videojs | 10 | registerSourceHandler(videojs) |
11 | require('@streamroot/videojs-hlsjs-plugin') | ||
12 | 11 | ||
13 | const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') | 12 | const Plugin = videojs.getPlugin('plugin') |
14 | class P2pMediaLoaderPlugin extends Plugin { | 13 | class P2pMediaLoaderPlugin extends Plugin { |
15 | 14 | ||
16 | private readonly CONSTANTS = { | 15 | private readonly CONSTANTS = { |
@@ -18,7 +17,7 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
18 | } | 17 | } |
19 | private readonly options: P2PMediaLoaderPluginOptions | 18 | private readonly options: P2PMediaLoaderPluginOptions |
20 | 19 | ||
21 | private hlsjs: any // Don't type hlsjs to not bundle the module | 20 | private hlsjs: Hlsjs |
22 | private p2pEngine: Engine | 21 | private p2pEngine: Engine |
23 | private statsP2PBytes = { | 22 | private statsP2PBytes = { |
24 | pendingDownload: [] as number[], | 23 | pendingDownload: [] as number[], |
@@ -37,12 +36,13 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
37 | 36 | ||
38 | private networkInfoInterval: any | 37 | private networkInfoInterval: any |
39 | 38 | ||
40 | constructor (player: videojs.Player, options: P2PMediaLoaderPluginOptions) { | 39 | constructor (player: VideoJsPlayer, options?: P2PMediaLoaderPluginOptions) { |
41 | super(player, options) | 40 | super(player) |
42 | 41 | ||
43 | this.options = options | 42 | this.options = options |
44 | 43 | ||
45 | if (!videojs.Html5Hlsjs) { | 44 | // FIXME: typings https://github.com/Microsoft/TypeScript/issues/14080 |
45 | if (!(videojs as any).Html5Hlsjs) { | ||
46 | const message = 'HLS.js does not seem to be supported.' | 46 | const message = 'HLS.js does not seem to be supported.' |
47 | console.warn(message) | 47 | console.warn(message) |
48 | 48 | ||
@@ -50,7 +50,8 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
50 | return | 50 | return |
51 | } | 51 | } |
52 | 52 | ||
53 | videojs.Html5Hlsjs.addHook('beforeinitialize', (videojsPlayer: any, hlsjs: any) => { | 53 | // FIXME: typings https://github.com/Microsoft/TypeScript/issues/14080 |
54 | (videojs as any).Html5Hlsjs.addHook('beforeinitialize', (videojsPlayer: any, hlsjs: any) => { | ||
54 | this.hlsjs = hlsjs | 55 | this.hlsjs = hlsjs |
55 | }) | 56 | }) |
56 | 57 | ||
@@ -84,12 +85,11 @@ class P2pMediaLoaderPlugin extends Plugin { | |||
84 | private initialize () { | 85 | private initialize () { |
85 | initHlsJsPlayer(this.hlsjs) | 86 | initHlsJsPlayer(this.hlsjs) |
86 | 87 | ||
87 | const tech = this.player.tech_ | 88 | // FIXME: typings |
88 | this.p2pEngine = tech.options_.hlsjsConfig.loader.getEngine() | 89 | const options = this.player.tech(true).options_ as any |
90 | this.p2pEngine = options.hlsjsConfig.loader.getEngine() | ||
89 | 91 | ||
90 | // Avoid using constants to not import hls.hs | 92 | this.hlsjs.on(Hlsjs.Events.LEVEL_SWITCHING, (_: any, data: any) => { |
91 | // https://github.com/video-dev/hls.js/blob/master/src/events.js#L37 | ||
92 | this.hlsjs.on('hlsLevelSwitching', (_: any, data: any) => { | ||
93 | this.trigger('resolutionChange', { auto: this.hlsjs.autoLevelEnabled, resolutionId: data.height }) | 93 | this.trigger('resolutionChange', { auto: this.hlsjs.autoLevelEnabled, resolutionId: data.height }) |
94 | }) | 94 | }) |
95 | 95 | ||
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index d9e02cd7d..dbf631a5e 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts | |||
@@ -1,21 +1,26 @@ | |||
1 | import { VideoFile } from '../../../../shared/models/videos' | 1 | import { VideoFile } from '../../../../shared/models/videos' |
2 | // @ts-ignore | 2 | import videojs, { VideoJsPlayer, VideoJsPlayerOptions } from 'video.js' |
3 | import * as videojs from 'video.js' | ||
4 | import 'videojs-hotkeys' | 3 | import 'videojs-hotkeys' |
5 | import 'videojs-dock' | 4 | import 'videojs-dock' |
6 | import 'videojs-contextmenu-ui' | 5 | import 'videojs-contextmenu-ui' |
7 | import 'videojs-contrib-quality-levels' | 6 | import 'videojs-contrib-quality-levels' |
7 | import './upnext/end-card' | ||
8 | import './upnext/upnext-plugin' | 8 | import './upnext/upnext-plugin' |
9 | import './bezels/bezels-plugin' | 9 | import './bezels/bezels-plugin' |
10 | import './peertube-plugin' | 10 | import './peertube-plugin' |
11 | import './videojs-components/next-video-button' | 11 | import './videojs-components/next-video-button' |
12 | import './videojs-components/p2p-info-button' | ||
12 | import './videojs-components/peertube-link-button' | 13 | import './videojs-components/peertube-link-button' |
14 | import './videojs-components/peertube-load-progress-bar' | ||
13 | import './videojs-components/resolution-menu-button' | 15 | import './videojs-components/resolution-menu-button' |
16 | import './videojs-components/resolution-menu-item' | ||
17 | import './videojs-components/settings-dialog' | ||
14 | import './videojs-components/settings-menu-button' | 18 | import './videojs-components/settings-menu-button' |
15 | import './videojs-components/p2p-info-button' | 19 | import './videojs-components/settings-menu-item' |
16 | import './videojs-components/peertube-load-progress-bar' | 20 | import './videojs-components/settings-panel' |
21 | import './videojs-components/settings-panel-child' | ||
17 | import './videojs-components/theater-button' | 22 | import './videojs-components/theater-button' |
18 | import { P2PMediaLoaderPluginOptions, UserWatching, VideoJSCaption, VideoJSPluginOptions, videojsUntyped } from './peertube-videojs-typings' | 23 | import { P2PMediaLoaderPluginOptions, UserWatching, VideoJSCaption, VideoJSPluginOptions } from './peertube-videojs-typings' |
19 | import { buildVideoEmbed, buildVideoLink, copyToClipboard, getRtcConfig } from './utils' | 24 | import { buildVideoEmbed, buildVideoLink, copyToClipboard, getRtcConfig } from './utils' |
20 | import { isDefaultLocale } from '../../../../shared/models/i18n/i18n' | 25 | import { isDefaultLocale } from '../../../../shared/models/i18n/i18n' |
21 | import { segmentValidatorFactory } from './p2p-media-loader/segment-validator' | 26 | import { segmentValidatorFactory } from './p2p-media-loader/segment-validator' |
@@ -24,12 +29,17 @@ import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager' | |||
24 | import { getStoredP2PEnabled } from './peertube-player-local-storage' | 29 | import { getStoredP2PEnabled } from './peertube-player-local-storage' |
25 | import { TranslationsManager } from './translations-manager' | 30 | import { TranslationsManager } from './translations-manager' |
26 | 31 | ||
32 | // For VideoJS | ||
33 | (window as any).WebVTT = require('vtt.js/lib/vtt.js').WebVTT; | ||
34 | |||
27 | // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) | 35 | // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) |
28 | videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' | 36 | (videojs.getComponent('PlaybackRateMenuButton') as any).prototype.controlText_ = 'Speed' |
37 | |||
38 | const CaptionsButton = videojs.getComponent('CaptionsButton') as any | ||
29 | // Change Captions to Subtitles/CC | 39 | // Change Captions to Subtitles/CC |
30 | videojsUntyped.getComponent('CaptionsButton').prototype.controlText_ = 'Subtitles/CC' | 40 | CaptionsButton.prototype.controlText_ = 'Subtitles/CC' |
31 | // We just want to display 'Off' instead of 'captions off', keep a space so the variable == true (hacky I know) | 41 | // We just want to display 'Off' instead of 'captions off', keep a space so the variable == true (hacky I know) |
32 | videojsUntyped.getComponent('CaptionsButton').prototype.label_ = ' ' | 42 | CaptionsButton.prototype.label_ = ' ' |
33 | 43 | ||
34 | export type PlayerMode = 'webtorrent' | 'p2p-media-loader' | 44 | export type PlayerMode = 'webtorrent' | 'p2p-media-loader' |
35 | 45 | ||
@@ -92,9 +102,9 @@ export type PeertubePlayerManagerOptions = { | |||
92 | 102 | ||
93 | export class PeertubePlayerManager { | 103 | export class PeertubePlayerManager { |
94 | private static playerElementClassName: string | 104 | private static playerElementClassName: string |
95 | private static onPlayerChange: (player: any) => void | 105 | private static onPlayerChange: (player: VideoJsPlayer) => void |
96 | 106 | ||
97 | static async initialize (mode: PlayerMode, options: PeertubePlayerManagerOptions, onPlayerChange: (player: any) => void) { | 107 | static async initialize (mode: PlayerMode, options: PeertubePlayerManagerOptions, onPlayerChange: (player: VideoJsPlayer) => void) { |
98 | let p2pMediaLoader: any | 108 | let p2pMediaLoader: any |
99 | 109 | ||
100 | this.onPlayerChange = onPlayerChange | 110 | this.onPlayerChange = onPlayerChange |
@@ -114,12 +124,12 @@ export class PeertubePlayerManager { | |||
114 | 124 | ||
115 | const self = this | 125 | const self = this |
116 | return new Promise(res => { | 126 | return new Promise(res => { |
117 | videojs(options.common.playerElement, videojsOptions, function (this: any) { | 127 | videojs(options.common.playerElement, videojsOptions, function (this: VideoJsPlayer) { |
118 | const player = this | 128 | const player = this |
119 | 129 | ||
120 | let alreadyFallback = false | 130 | let alreadyFallback = false |
121 | 131 | ||
122 | player.tech_.one('error', () => { | 132 | player.tech(true).one('error', () => { |
123 | if (!alreadyFallback) self.maybeFallbackToWebTorrent(mode, player, options) | 133 | if (!alreadyFallback) self.maybeFallbackToWebTorrent(mode, player, options) |
124 | alreadyFallback = true | 134 | alreadyFallback = true |
125 | }) | 135 | }) |
@@ -164,7 +174,7 @@ export class PeertubePlayerManager { | |||
164 | const videojsOptions = this.getVideojsOptions(mode, options) | 174 | const videojsOptions = this.getVideojsOptions(mode, options) |
165 | 175 | ||
166 | const self = this | 176 | const self = this |
167 | videojs(newVideoElement, videojsOptions, function (this: any) { | 177 | videojs(newVideoElement, videojsOptions, function (this: VideoJsPlayer) { |
168 | const player = this | 178 | const player = this |
169 | 179 | ||
170 | self.addContextMenu(mode, player, options.common.embedUrl) | 180 | self.addContextMenu(mode, player, options.common.embedUrl) |
@@ -173,7 +183,11 @@ export class PeertubePlayerManager { | |||
173 | }) | 183 | }) |
174 | } | 184 | } |
175 | 185 | ||
176 | private static getVideojsOptions (mode: PlayerMode, options: PeertubePlayerManagerOptions, p2pMediaLoaderModule?: any) { | 186 | private static getVideojsOptions ( |
187 | mode: PlayerMode, | ||
188 | options: PeertubePlayerManagerOptions, | ||
189 | p2pMediaLoaderModule?: any | ||
190 | ): VideoJsPlayerOptions { | ||
177 | const commonOptions = options.common | 191 | const commonOptions = options.common |
178 | 192 | ||
179 | let autoplay = commonOptions.autoplay | 193 | let autoplay = commonOptions.autoplay |
@@ -197,9 +211,9 @@ export class PeertubePlayerManager { | |||
197 | } | 211 | } |
198 | 212 | ||
199 | if (mode === 'p2p-media-loader') { | 213 | if (mode === 'p2p-media-loader') { |
200 | const { streamrootHls } = PeertubePlayerManager.addP2PMediaLoaderOptions(plugins, options, p2pMediaLoaderModule) | 214 | const { hlsjs } = PeertubePlayerManager.addP2PMediaLoaderOptions(plugins, options, p2pMediaLoaderModule) |
201 | 215 | ||
202 | html5 = streamrootHls.html5 | 216 | html5 = hlsjs.html5 |
203 | } | 217 | } |
204 | 218 | ||
205 | if (mode === 'webtorrent') { | 219 | if (mode === 'webtorrent') { |
@@ -213,7 +227,7 @@ export class PeertubePlayerManager { | |||
213 | html5, | 227 | html5, |
214 | 228 | ||
215 | // We don't use text track settings for now | 229 | // We don't use text track settings for now |
216 | textTrackSettings: false, | 230 | textTrackSettings: false as any, // FIXME: typings |
217 | controls: commonOptions.controls !== undefined ? commonOptions.controls : true, | 231 | controls: commonOptions.controls !== undefined ? commonOptions.controls : true, |
218 | loop: commonOptions.loop !== undefined ? commonOptions.loop : false, | 232 | loop: commonOptions.loop !== undefined ? commonOptions.loop : false, |
219 | 233 | ||
@@ -237,7 +251,7 @@ export class PeertubePlayerManager { | |||
237 | peertubeLink: commonOptions.peertubeLink, | 251 | peertubeLink: commonOptions.peertubeLink, |
238 | theaterButton: commonOptions.theaterButton, | 252 | theaterButton: commonOptions.theaterButton, |
239 | nextVideo: commonOptions.nextVideo | 253 | nextVideo: commonOptions.nextVideo |
240 | }) | 254 | }) as any // FIXME: typings |
241 | } | 255 | } |
242 | } | 256 | } |
243 | 257 | ||
@@ -289,7 +303,7 @@ export class PeertubePlayerManager { | |||
289 | swarmId: p2pMediaLoaderOptions.playlistUrl | 303 | swarmId: p2pMediaLoaderOptions.playlistUrl |
290 | } | 304 | } |
291 | } | 305 | } |
292 | const streamrootHls = { | 306 | const hlsjs = { |
293 | levelLabelHandler: (level: { height: number, width: number }) => { | 307 | levelLabelHandler: (level: { height: number, width: number }) => { |
294 | const file = p2pMediaLoaderOptions.videoFiles.find(f => f.resolution.id === level.height) | 308 | const file = p2pMediaLoaderOptions.videoFiles.find(f => f.resolution.id === level.height) |
295 | 309 | ||
@@ -308,7 +322,7 @@ export class PeertubePlayerManager { | |||
308 | } | 322 | } |
309 | } | 323 | } |
310 | 324 | ||
311 | const toAssign = { p2pMediaLoader, streamrootHls } | 325 | const toAssign = { p2pMediaLoader, hlsjs } |
312 | Object.assign(plugins, toAssign) | 326 | Object.assign(plugins, toAssign) |
313 | 327 | ||
314 | return toAssign | 328 | return toAssign |
@@ -406,7 +420,7 @@ export class PeertubePlayerManager { | |||
406 | return children | 420 | return children |
407 | } | 421 | } |
408 | 422 | ||
409 | private static addContextMenu (mode: PlayerMode, player: any, videoEmbedUrl: string) { | 423 | private static addContextMenu (mode: PlayerMode, player: VideoJsPlayer, videoEmbedUrl: string) { |
410 | const content = [ | 424 | const content = [ |
411 | { | 425 | { |
412 | label: player.localize('Copy the video URL'), | 426 | label: player.localize('Copy the video URL'), |
@@ -416,9 +430,8 @@ export class PeertubePlayerManager { | |||
416 | }, | 430 | }, |
417 | { | 431 | { |
418 | label: player.localize('Copy the video URL at the current time'), | 432 | label: player.localize('Copy the video URL at the current time'), |
419 | listener: function () { | 433 | listener: function (this: VideoJsPlayer) { |
420 | const player = this as videojs.Player | 434 | copyToClipboard(buildVideoLink({ startTime: this.currentTime() })) |
421 | copyToClipboard(buildVideoLink({ startTime: player.currentTime() })) | ||
422 | } | 435 | } |
423 | }, | 436 | }, |
424 | { | 437 | { |
@@ -432,9 +445,8 @@ export class PeertubePlayerManager { | |||
432 | if (mode === 'webtorrent') { | 445 | if (mode === 'webtorrent') { |
433 | content.push({ | 446 | content.push({ |
434 | label: player.localize('Copy magnet URI'), | 447 | label: player.localize('Copy magnet URI'), |
435 | listener: function () { | 448 | listener: function (this: VideoJsPlayer) { |
436 | const player = this as videojs.Player | 449 | copyToClipboard(this.webtorrent().getCurrentVideoFile().magnetUri) |
437 | copyToClipboard(player.webtorrent().getCurrentVideoFile().magnetUri) | ||
438 | } | 450 | } |
439 | }) | 451 | }) |
440 | } | 452 | } |
@@ -472,7 +484,8 @@ export class PeertubePlayerManager { | |||
472 | return event.key === '>' | 484 | return event.key === '>' |
473 | }, | 485 | }, |
474 | handler: function (player: videojs.Player) { | 486 | handler: function (player: videojs.Player) { |
475 | player.playbackRate((player.playbackRate() + 0.1).toFixed(2)) | 487 | const newValue = Math.min(player.playbackRate() + 0.1, 5) |
488 | player.playbackRate(parseFloat(newValue.toFixed(2))) | ||
476 | } | 489 | } |
477 | }, | 490 | }, |
478 | decreasePlaybackRateKey: { | 491 | decreasePlaybackRateKey: { |
@@ -480,7 +493,8 @@ export class PeertubePlayerManager { | |||
480 | return event.key === '<' | 493 | return event.key === '<' |
481 | }, | 494 | }, |
482 | handler: function (player: videojs.Player) { | 495 | handler: function (player: videojs.Player) { |
483 | player.playbackRate((player.playbackRate() - 0.1).toFixed(2)) | 496 | const newValue = Math.max(player.playbackRate() - 0.1, 0.10) |
497 | player.playbackRate(parseFloat(newValue.toFixed(2))) | ||
484 | } | 498 | } |
485 | }, | 499 | }, |
486 | frameByFrame: { | 500 | frameByFrame: { |
diff --git a/client/src/assets/player/peertube-plugin.ts b/client/src/assets/player/peertube-plugin.ts index 9824c43b5..19d104676 100644 --- a/client/src/assets/player/peertube-plugin.ts +++ b/client/src/assets/player/peertube-plugin.ts | |||
@@ -1,14 +1,10 @@ | |||
1 | // FIXME: something weird with our path definition in tsconfig and typings | 1 | import videojs, { VideoJsPlayer } from 'video.js' |
2 | // @ts-ignore | ||
3 | import * as videojs from 'video.js' | ||
4 | import './videojs-components/settings-menu-button' | 2 | import './videojs-components/settings-menu-button' |
5 | import { | 3 | import { |
6 | PeerTubePluginOptions, | 4 | PeerTubePluginOptions, |
7 | ResolutionUpdateData, | 5 | ResolutionUpdateData, |
8 | UserWatching, | 6 | UserWatching, |
9 | VideoJSCaption, | 7 | VideoJSCaption |
10 | VideoJSComponentInterface, | ||
11 | videojsUntyped | ||
12 | } from './peertube-videojs-typings' | 8 | } from './peertube-videojs-typings' |
13 | import { isMobile, timeToInt } from './utils' | 9 | import { isMobile, timeToInt } from './utils' |
14 | import { | 10 | import { |
@@ -20,7 +16,8 @@ import { | |||
20 | saveVolumeInStore | 16 | saveVolumeInStore |
21 | } from './peertube-player-local-storage' | 17 | } from './peertube-player-local-storage' |
22 | 18 | ||
23 | const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') | 19 | const Plugin = videojs.getPlugin('plugin') |
20 | |||
24 | class PeerTubePlugin extends Plugin { | 21 | class PeerTubePlugin extends Plugin { |
25 | private readonly videoViewUrl: string | 22 | private readonly videoViewUrl: string |
26 | private readonly videoDuration: number | 23 | private readonly videoDuration: number |
@@ -28,7 +25,6 @@ class PeerTubePlugin extends Plugin { | |||
28 | USER_WATCHING_VIDEO_INTERVAL: 5000 // Every 5 seconds, notify the user is watching the video | 25 | USER_WATCHING_VIDEO_INTERVAL: 5000 // Every 5 seconds, notify the user is watching the video |
29 | } | 26 | } |
30 | 27 | ||
31 | private player: any | ||
32 | private videoCaptions: VideoJSCaption[] | 28 | private videoCaptions: VideoJSCaption[] |
33 | private defaultSubtitle: string | 29 | private defaultSubtitle: string |
34 | 30 | ||
@@ -40,8 +36,8 @@ class PeerTubePlugin extends Plugin { | |||
40 | private mouseInControlBar = false | 36 | private mouseInControlBar = false |
41 | private readonly savedInactivityTimeout: number | 37 | private readonly savedInactivityTimeout: number |
42 | 38 | ||
43 | constructor (player: videojs.Player, options: PeerTubePluginOptions) { | 39 | constructor (player: VideoJsPlayer, options?: PeerTubePluginOptions) { |
44 | super(player, options) | 40 | super(player) |
45 | 41 | ||
46 | this.videoViewUrl = options.videoViewUrl | 42 | this.videoViewUrl = options.videoViewUrl |
47 | this.videoDuration = options.videoDuration | 43 | this.videoDuration = options.videoDuration |
@@ -67,7 +63,7 @@ class PeerTubePlugin extends Plugin { | |||
67 | this.player.p2pMediaLoader().on('resolutionChange', (_: any, d: any) => this.handleResolutionChange(d)) | 63 | this.player.p2pMediaLoader().on('resolutionChange', (_: any, d: any) => this.handleResolutionChange(d)) |
68 | } | 64 | } |
69 | 65 | ||
70 | this.player.tech_.on('loadedqualitydata', () => { | 66 | this.player.tech(true).on('loadedqualitydata', () => { |
71 | setTimeout(() => { | 67 | setTimeout(() => { |
72 | // Replay a resolution change, now we loaded all quality data | 68 | // Replay a resolution change, now we loaded all quality data |
73 | if (this.lastResolutionChange) this.handleResolutionChange(this.lastResolutionChange) | 69 | if (this.lastResolutionChange) this.handleResolutionChange(this.lastResolutionChange) |
@@ -102,7 +98,7 @@ class PeerTubePlugin extends Plugin { | |||
102 | } | 98 | } |
103 | 99 | ||
104 | this.player.textTracks().on('change', () => { | 100 | this.player.textTracks().on('change', () => { |
105 | const showing = this.player.textTracks().tracks_.find((t: { kind: string, mode: string }) => { | 101 | const showing = this.player.textTracks().tracks_.find(t => { |
106 | return t.kind === 'captions' && t.mode === 'showing' | 102 | return t.kind === 'captions' && t.mode === 'showing' |
107 | }) | 103 | }) |
108 | 104 | ||
@@ -262,7 +258,7 @@ class PeerTubePlugin extends Plugin { | |||
262 | 258 | ||
263 | // Thanks: https://github.com/videojs/video.js/issues/4460#issuecomment-312861657 | 259 | // Thanks: https://github.com/videojs/video.js/issues/4460#issuecomment-312861657 |
264 | private initSmoothProgressBar () { | 260 | private initSmoothProgressBar () { |
265 | const SeekBar = videojsUntyped.getComponent('SeekBar') | 261 | const SeekBar = videojs.getComponent('SeekBar') as any |
266 | SeekBar.prototype.getPercent = function getPercent () { | 262 | SeekBar.prototype.getPercent = function getPercent () { |
267 | // Allows for smooth scrubbing, when player can't keep up. | 263 | // Allows for smooth scrubbing, when player can't keep up. |
268 | // const time = (this.player_.scrubbing()) ? | 264 | // const time = (this.player_.scrubbing()) ? |
diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts index aad4dbb4f..a4e4c580c 100644 --- a/client/src/assets/player/peertube-videojs-typings.ts +++ b/client/src/assets/player/peertube-videojs-typings.ts | |||
@@ -1,28 +1,81 @@ | |||
1 | // FIXME: something weird with our path definition in tsconfig and typings | ||
2 | // @ts-ignore | ||
3 | import * as videojs from 'video.js' | ||
4 | |||
5 | import { PeerTubePlugin } from './peertube-plugin' | 1 | import { PeerTubePlugin } from './peertube-plugin' |
6 | import { WebTorrentPlugin } from './webtorrent/webtorrent-plugin' | 2 | import { WebTorrentPlugin } from './webtorrent/webtorrent-plugin' |
7 | import { P2pMediaLoaderPlugin } from './p2p-media-loader/p2p-media-loader-plugin' | 3 | import { P2pMediaLoaderPlugin } from './p2p-media-loader/p2p-media-loader-plugin' |
8 | import { PlayerMode } from './peertube-player-manager' | 4 | import { PlayerMode } from './peertube-player-manager' |
9 | import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager' | 5 | import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager' |
10 | import { VideoFile } from '@shared/models' | 6 | import { VideoFile } from '@shared/models' |
7 | import videojs from 'video.js' | ||
8 | import { Config, Level } from 'hls.js' | ||
9 | |||
10 | declare module 'video.js' { | ||
11 | |||
12 | export interface VideoJsPlayer { | ||
13 | srOptions_: HlsjsConfigHandlerOptions | ||
14 | |||
15 | theaterEnabled: boolean | ||
16 | |||
17 | // FIXME: add it to upstream typings | ||
18 | posterImage: { | ||
19 | show (): void | ||
20 | hide (): void | ||
21 | } | ||
22 | |||
23 | handleTechSeeked_ (): void | ||
24 | |||
25 | // Plugins | ||
11 | 26 | ||
12 | declare namespace videojs { | ||
13 | interface Player { | ||
14 | peertube (): PeerTubePlugin | 27 | peertube (): PeerTubePlugin |
28 | |||
15 | webtorrent (): WebTorrentPlugin | 29 | webtorrent (): WebTorrentPlugin |
30 | |||
16 | p2pMediaLoader (): P2pMediaLoaderPlugin | 31 | p2pMediaLoader (): P2pMediaLoaderPlugin |
32 | |||
33 | contextmenuUI (options: any): any | ||
34 | |||
35 | bezels (): void | ||
36 | |||
37 | qualityLevels (): QualityLevels | ||
38 | |||
39 | textTracks (): TextTrackList & { | ||
40 | on: Function | ||
41 | tracks_: { kind: string, mode: string, language: string }[] | ||
42 | } | ||
43 | |||
44 | audioTracks (): AudioTrackList | ||
45 | |||
46 | dock (options: { title: string, description: string }): void | ||
17 | } | 47 | } |
18 | } | 48 | } |
19 | 49 | ||
20 | interface VideoJSComponentInterface { | 50 | export interface VideoJSTechHLS extends videojs.Tech { |
21 | _player: videojs.Player | 51 | hlsProvider: any // FIXME: typings |
52 | } | ||
53 | |||
54 | export interface HlsjsConfigHandlerOptions { | ||
55 | hlsjsConfig?: Config & { cueHandler: any }// FIXME: typings | ||
56 | captionConfig?: any // FIXME: typings | ||
57 | |||
58 | levelLabelHandler?: (level: Level) => string | ||
59 | } | ||
60 | |||
61 | type QualityLevelRepresentation = { | ||
62 | id: number | ||
63 | height: number | ||
64 | |||
65 | label?: string | ||
66 | width?: number | ||
67 | bandwidth?: number | ||
68 | bitrate?: number | ||
22 | 69 | ||
23 | new (player: videojs.Player, options?: any): any | 70 | enabled?: Function |
71 | _enabled: boolean | ||
72 | } | ||
73 | |||
74 | type QualityLevels = QualityLevelRepresentation[] & { | ||
75 | selectedIndex: number | ||
76 | selectedIndex_: number | ||
24 | 77 | ||
25 | registerComponent (name: string, obj: any): any | 78 | addQualityLevel (representation: QualityLevelRepresentation): void |
26 | } | 79 | } |
27 | 80 | ||
28 | type VideoJSCaption = { | 81 | type VideoJSCaption = { |
@@ -78,9 +131,6 @@ type VideoJSPluginOptions = { | |||
78 | p2pMediaLoader?: P2PMediaLoaderPluginOptions | 131 | p2pMediaLoader?: P2PMediaLoaderPluginOptions |
79 | } | 132 | } |
80 | 133 | ||
81 | // videojs typings don't have some method we need | ||
82 | const videojsUntyped = videojs as any | ||
83 | |||
84 | type LoadedQualityData = { | 134 | type LoadedQualityData = { |
85 | qualitySwitchCallback: Function, | 135 | qualitySwitchCallback: Function, |
86 | qualityData: { | 136 | qualityData: { |
@@ -123,13 +173,13 @@ export { | |||
123 | PlayerNetworkInfo, | 173 | PlayerNetworkInfo, |
124 | ResolutionUpdateData, | 174 | ResolutionUpdateData, |
125 | AutoResolutionUpdateData, | 175 | AutoResolutionUpdateData, |
126 | VideoJSComponentInterface, | ||
127 | videojsUntyped, | ||
128 | VideoJSCaption, | 176 | VideoJSCaption, |
129 | UserWatching, | 177 | UserWatching, |
130 | PeerTubePluginOptions, | 178 | PeerTubePluginOptions, |
131 | WebtorrentPluginOptions, | 179 | WebtorrentPluginOptions, |
132 | P2PMediaLoaderPluginOptions, | 180 | P2PMediaLoaderPluginOptions, |
133 | VideoJSPluginOptions, | 181 | VideoJSPluginOptions, |
134 | LoadedQualityData | 182 | LoadedQualityData, |
183 | QualityLevelRepresentation, | ||
184 | QualityLevels | ||
135 | } | 185 | } |
diff --git a/client/src/assets/player/upnext/end-card.ts b/client/src/assets/player/upnext/end-card.ts new file mode 100644 index 000000000..d121a83a9 --- /dev/null +++ b/client/src/assets/player/upnext/end-card.ts | |||
@@ -0,0 +1,155 @@ | |||
1 | import videojs, { VideoJsPlayer } from 'video.js' | ||
2 | |||
3 | function getMainTemplate (options: any) { | ||
4 | return ` | ||
5 | <div class="vjs-upnext-top"> | ||
6 | <span class="vjs-upnext-headtext">${options.headText}</span> | ||
7 | <div class="vjs-upnext-title"></div> | ||
8 | </div> | ||
9 | <div class="vjs-upnext-autoplay-icon"> | ||
10 | <svg height="100%" version="1.1" viewbox="0 0 98 98" width="100%"> | ||
11 | <circle class="vjs-upnext-svg-autoplay-circle" cx="49" cy="49" fill="#000" fill-opacity="0.8" r="48"></circle> | ||
12 | <circle class="vjs-upnext-svg-autoplay-ring" cx="-49" cy="49" fill-opacity="0" r="46.5" stroke="#FFFFFF" stroke-width="4" transform="rotate(-90)"></circle> | ||
13 | <polygon class="vjs-upnext-svg-autoplay-triangle" fill="#fff" points="32,27 72,49 32,71"></polygon></svg> | ||
14 | </div> | ||
15 | <span class="vjs-upnext-bottom"> | ||
16 | <span class="vjs-upnext-cancel"> | ||
17 | <button class="vjs-upnext-cancel-button" tabindex="0" aria-label="Cancel autoplay">${options.cancelText}</button> | ||
18 | </span> | ||
19 | <span class="vjs-upnext-suspended">${options.suspendedText}</span> | ||
20 | </span> | ||
21 | ` | ||
22 | } | ||
23 | |||
24 | export interface EndCardOptions extends videojs.ComponentOptions { | ||
25 | next: Function, | ||
26 | getTitle: () => string | ||
27 | timeout: number | ||
28 | cancelText: string | ||
29 | headText: string | ||
30 | suspendedText: string | ||
31 | condition: () => boolean | ||
32 | suspended: () => boolean | ||
33 | } | ||
34 | |||
35 | const Component = videojs.getComponent('Component') | ||
36 | class EndCard extends Component { | ||
37 | options_: EndCardOptions | ||
38 | |||
39 | dashOffsetTotal = 586 | ||
40 | dashOffsetStart = 293 | ||
41 | interval = 50 | ||
42 | upNextEvents = new videojs.EventTarget() | ||
43 | ticks = 0 | ||
44 | totalTicks: number | ||
45 | |||
46 | container: HTMLDivElement | ||
47 | title: HTMLElement | ||
48 | autoplayRing: HTMLElement | ||
49 | cancelButton: HTMLElement | ||
50 | suspendedMessage: HTMLElement | ||
51 | nextButton: HTMLElement | ||
52 | |||
53 | constructor (player: VideoJsPlayer, options: EndCardOptions) { | ||
54 | super(player, options) | ||
55 | |||
56 | this.totalTicks = this.options_.timeout / this.interval | ||
57 | |||
58 | player.on('ended', (_: any) => { | ||
59 | if (!this.options_.condition()) return | ||
60 | |||
61 | player.addClass('vjs-upnext--showing') | ||
62 | this.showCard((canceled: boolean) => { | ||
63 | player.removeClass('vjs-upnext--showing') | ||
64 | this.container.style.display = 'none' | ||
65 | if (!canceled) { | ||
66 | this.options_.next() | ||
67 | } | ||
68 | }) | ||
69 | }) | ||
70 | |||
71 | player.on('playing', () => { | ||
72 | this.upNextEvents.trigger('playing') | ||
73 | }) | ||
74 | } | ||
75 | |||
76 | createEl () { | ||
77 | const container = super.createEl('div', { | ||
78 | className: 'vjs-upnext-content', | ||
79 | innerHTML: getMainTemplate(this.options_) | ||
80 | }) as HTMLDivElement | ||
81 | |||
82 | this.container = container | ||
83 | container.style.display = 'none' | ||
84 | |||
85 | this.autoplayRing = container.getElementsByClassName('vjs-upnext-svg-autoplay-ring')[0] as HTMLElement | ||
86 | this.title = container.getElementsByClassName('vjs-upnext-title')[0] as HTMLElement | ||
87 | this.cancelButton = container.getElementsByClassName('vjs-upnext-cancel-button')[0] as HTMLElement | ||
88 | this.suspendedMessage = container.getElementsByClassName('vjs-upnext-suspended')[0] as HTMLElement | ||
89 | this.nextButton = container.getElementsByClassName('vjs-upnext-autoplay-icon')[0] as HTMLElement | ||
90 | |||
91 | this.cancelButton.onclick = () => { | ||
92 | this.upNextEvents.trigger('cancel') | ||
93 | } | ||
94 | |||
95 | this.nextButton.onclick = () => { | ||
96 | this.upNextEvents.trigger('next') | ||
97 | } | ||
98 | |||
99 | return container | ||
100 | } | ||
101 | |||
102 | showCard (cb: Function) { | ||
103 | let timeout: any | ||
104 | |||
105 | this.autoplayRing.setAttribute('stroke-dasharray', '' + this.dashOffsetStart) | ||
106 | this.autoplayRing.setAttribute('stroke-dashoffset', '' + -this.dashOffsetStart) | ||
107 | |||
108 | this.title.innerHTML = this.options_.getTitle() | ||
109 | |||
110 | this.upNextEvents.one('cancel', () => { | ||
111 | clearTimeout(timeout) | ||
112 | cb(true) | ||
113 | }) | ||
114 | |||
115 | this.upNextEvents.one('playing', () => { | ||
116 | clearTimeout(timeout) | ||
117 | cb(true) | ||
118 | }) | ||
119 | |||
120 | this.upNextEvents.one('next', () => { | ||
121 | clearTimeout(timeout) | ||
122 | cb(false) | ||
123 | }) | ||
124 | |||
125 | const goToPercent = (percent: number) => { | ||
126 | const newOffset = Math.max(-this.dashOffsetTotal, - this.dashOffsetStart - percent * this.dashOffsetTotal / 2 / 100) | ||
127 | this.autoplayRing.setAttribute('stroke-dashoffset', '' + newOffset) | ||
128 | } | ||
129 | |||
130 | const tick = () => { | ||
131 | goToPercent((this.ticks++) * 100 / this.totalTicks) | ||
132 | } | ||
133 | |||
134 | const update = () => { | ||
135 | if (this.options_.suspended()) { | ||
136 | this.suspendedMessage.innerText = this.options_.suspendedText | ||
137 | goToPercent(0) | ||
138 | this.ticks = 0 | ||
139 | timeout = setTimeout(update.bind(this), 300) // checks once supsended can be a bit longer | ||
140 | } else if (this.ticks >= this.totalTicks) { | ||
141 | clearTimeout(timeout) | ||
142 | cb(false) | ||
143 | } else { | ||
144 | this.suspendedMessage.innerText = '' | ||
145 | tick() | ||
146 | timeout = setTimeout(update.bind(this), this.interval) | ||
147 | } | ||
148 | } | ||
149 | |||
150 | this.container.style.display = 'block' | ||
151 | timeout = setTimeout(update.bind(this), this.interval) | ||
152 | } | ||
153 | } | ||
154 | |||
155 | videojs.registerComponent('EndCard', EndCard) | ||
diff --git a/client/src/assets/player/upnext/upnext-plugin.ts b/client/src/assets/player/upnext/upnext-plugin.ts index a3747b25f..6512fec2c 100644 --- a/client/src/assets/player/upnext/upnext-plugin.ts +++ b/client/src/assets/player/upnext/upnext-plugin.ts | |||
@@ -1,154 +1,11 @@ | |||
1 | // @ts-ignore | 1 | import videojs, { VideoJsPlayer } from 'video.js' |
2 | import * as videojs from 'video.js' | 2 | import { EndCardOptions } from './end-card' |
3 | import { VideoJSComponentInterface } from '../peertube-videojs-typings' | ||
4 | 3 | ||
5 | function getMainTemplate (options: any) { | 4 | const Plugin = videojs.getPlugin('plugin') |
6 | return ` | ||
7 | <div class="vjs-upnext-top"> | ||
8 | <span class="vjs-upnext-headtext">${options.headText}</span> | ||
9 | <div class="vjs-upnext-title"></div> | ||
10 | </div> | ||
11 | <div class="vjs-upnext-autoplay-icon"> | ||
12 | <svg height="100%" version="1.1" viewbox="0 0 98 98" width="100%"> | ||
13 | <circle class="vjs-upnext-svg-autoplay-circle" cx="49" cy="49" fill="#000" fill-opacity="0.8" r="48"></circle> | ||
14 | <circle class="vjs-upnext-svg-autoplay-ring" cx="-49" cy="49" fill-opacity="0" r="46.5" stroke="#FFFFFF" stroke-width="4" transform="rotate(-90)"></circle> | ||
15 | <polygon class="vjs-upnext-svg-autoplay-triangle" fill="#fff" points="32,27 72,49 32,71"></polygon></svg> | ||
16 | </div> | ||
17 | <span class="vjs-upnext-bottom"> | ||
18 | <span class="vjs-upnext-cancel"> | ||
19 | <button class="vjs-upnext-cancel-button" tabindex="0" aria-label="Cancel autoplay">${options.cancelText}</button> | ||
20 | </span> | ||
21 | <span class="vjs-upnext-suspended">${options.suspendedText}</span> | ||
22 | </span> | ||
23 | ` | ||
24 | } | ||
25 | |||
26 | // @ts-ignore-start | ||
27 | const Component = videojs.getComponent('Component') | ||
28 | class EndCard extends Component { | ||
29 | options_: any | ||
30 | dashOffsetTotal = 586 | ||
31 | dashOffsetStart = 293 | ||
32 | interval = 50 | ||
33 | upNextEvents = new videojs.EventTarget() | ||
34 | ticks = 0 | ||
35 | totalTicks: number | ||
36 | |||
37 | container: HTMLElement | ||
38 | title: HTMLElement | ||
39 | autoplayRing: HTMLElement | ||
40 | cancelButton: HTMLElement | ||
41 | suspendedMessage: HTMLElement | ||
42 | nextButton: HTMLElement | ||
43 | |||
44 | constructor (player: videojs.Player, options: any) { | ||
45 | super(player, options) | ||
46 | |||
47 | this.totalTicks = this.options_.timeout / this.interval | ||
48 | |||
49 | player.on('ended', (_: any) => { | ||
50 | if (!this.options_.condition()) return | ||
51 | |||
52 | player.addClass('vjs-upnext--showing') | ||
53 | this.showCard((canceled: boolean) => { | ||
54 | player.removeClass('vjs-upnext--showing') | ||
55 | this.container.style.display = 'none' | ||
56 | if (!canceled) { | ||
57 | this.options_.next() | ||
58 | } | ||
59 | }) | ||
60 | }) | ||
61 | |||
62 | player.on('playing', () => { | ||
63 | this.upNextEvents.trigger('playing') | ||
64 | }) | ||
65 | } | ||
66 | |||
67 | createEl () { | ||
68 | const container = super.createEl('div', { | ||
69 | className: 'vjs-upnext-content', | ||
70 | innerHTML: getMainTemplate(this.options_) | ||
71 | }) | ||
72 | |||
73 | this.container = container | ||
74 | container.style.display = 'none' | ||
75 | |||
76 | this.autoplayRing = container.getElementsByClassName('vjs-upnext-svg-autoplay-ring')[0] | ||
77 | this.title = container.getElementsByClassName('vjs-upnext-title')[0] | ||
78 | this.cancelButton = container.getElementsByClassName('vjs-upnext-cancel-button')[0] | ||
79 | this.suspendedMessage = container.getElementsByClassName('vjs-upnext-suspended')[0] | ||
80 | this.nextButton = container.getElementsByClassName('vjs-upnext-autoplay-icon')[0] | ||
81 | |||
82 | this.cancelButton.onclick = () => { | ||
83 | this.upNextEvents.trigger('cancel') | ||
84 | } | ||
85 | |||
86 | this.nextButton.onclick = () => { | ||
87 | this.upNextEvents.trigger('next') | ||
88 | } | ||
89 | |||
90 | return container | ||
91 | } | ||
92 | 5 | ||
93 | showCard (cb: Function) { | ||
94 | let timeout: any | ||
95 | |||
96 | this.autoplayRing.setAttribute('stroke-dasharray', '' + this.dashOffsetStart) | ||
97 | this.autoplayRing.setAttribute('stroke-dashoffset', '' + -this.dashOffsetStart) | ||
98 | |||
99 | this.title.innerHTML = this.options_.getTitle() | ||
100 | |||
101 | this.upNextEvents.one('cancel', () => { | ||
102 | clearTimeout(timeout) | ||
103 | cb(true) | ||
104 | }) | ||
105 | |||
106 | this.upNextEvents.one('playing', () => { | ||
107 | clearTimeout(timeout) | ||
108 | cb(true) | ||
109 | }) | ||
110 | |||
111 | this.upNextEvents.one('next', () => { | ||
112 | clearTimeout(timeout) | ||
113 | cb(false) | ||
114 | }) | ||
115 | |||
116 | const goToPercent = (percent: number) => { | ||
117 | const newOffset = Math.max(-this.dashOffsetTotal, - this.dashOffsetStart - percent * this.dashOffsetTotal / 2 / 100) | ||
118 | this.autoplayRing.setAttribute('stroke-dashoffset', '' + newOffset) | ||
119 | } | ||
120 | |||
121 | const tick = () => { | ||
122 | goToPercent((this.ticks++) * 100 / this.totalTicks) | ||
123 | } | ||
124 | |||
125 | const update = () => { | ||
126 | if (this.options_.suspended()) { | ||
127 | this.suspendedMessage.innerText = this.options_.suspendedText | ||
128 | goToPercent(0) | ||
129 | this.ticks = 0 | ||
130 | timeout = setTimeout(update.bind(this), 300) // checks once supsended can be a bit longer | ||
131 | } else if (this.ticks >= this.totalTicks) { | ||
132 | clearTimeout(timeout) | ||
133 | cb(false) | ||
134 | } else { | ||
135 | this.suspendedMessage.innerText = '' | ||
136 | tick() | ||
137 | timeout = setTimeout(update.bind(this), this.interval) | ||
138 | } | ||
139 | } | ||
140 | |||
141 | this.container.style.display = 'block' | ||
142 | timeout = setTimeout(update.bind(this), this.interval) | ||
143 | } | ||
144 | } | ||
145 | // @ts-ignore-end | ||
146 | |||
147 | videojs.registerComponent('EndCard', EndCard) | ||
148 | |||
149 | const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') | ||
150 | class UpNextPlugin extends Plugin { | 6 | class UpNextPlugin extends Plugin { |
151 | constructor (player: videojs.Player, options: any = {}) { | 7 | |
8 | constructor (player: VideoJsPlayer, options: Partial<EndCardOptions> = {}) { | ||
152 | const settings = { | 9 | const settings = { |
153 | next: options.next, | 10 | next: options.next, |
154 | getTitle: options.getTitle, | 11 | getTitle: options.getTitle, |
@@ -160,7 +17,7 @@ class UpNextPlugin extends Plugin { | |||
160 | suspended: options.suspended | 17 | suspended: options.suspended |
161 | } | 18 | } |
162 | 19 | ||
163 | super(player, settings) | 20 | super(player) |
164 | 21 | ||
165 | this.player.ready(() => { | 22 | this.player.ready(() => { |
166 | player.addClass('vjs-upnext') | 23 | player.addClass('vjs-upnext') |
diff --git a/client/src/assets/player/videojs-components/next-video-button.ts b/client/src/assets/player/videojs-components/next-video-button.ts index bf5c1aba4..bdb245dcc 100644 --- a/client/src/assets/player/videojs-components/next-video-button.ts +++ b/client/src/assets/player/videojs-components/next-video-button.ts | |||
@@ -1,21 +1,25 @@ | |||
1 | import { VideoJSComponentInterface, videojsUntyped } from '../peertube-videojs-typings' | 1 | import videojs, { VideoJsPlayer } from 'video.js' |
2 | // FIXME: something weird with our path definition in tsconfig and typings | ||
3 | // @ts-ignore | ||
4 | import { Player } from 'video.js' | ||
5 | 2 | ||
6 | const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button') | 3 | const Button = videojs.getComponent('Button') |
4 | |||
5 | export interface NextVideoButtonOptions extends videojs.ComponentOptions { | ||
6 | handler: Function | ||
7 | } | ||
7 | 8 | ||
8 | class NextVideoButton extends Button { | 9 | class NextVideoButton extends Button { |
10 | private readonly nextVideoButtonOptions: NextVideoButtonOptions | ||
9 | 11 | ||
10 | constructor (player: Player, options: any) { | 12 | constructor (player: VideoJsPlayer, options?: NextVideoButtonOptions) { |
11 | super(player, options) | 13 | super(player, options) |
14 | |||
15 | this.nextVideoButtonOptions = options | ||
12 | } | 16 | } |
13 | 17 | ||
14 | createEl () { | 18 | createEl () { |
15 | const button = videojsUntyped.dom.createEl('button', { | 19 | const button = videojs.dom.createEl('button', { |
16 | className: 'vjs-next-video' | 20 | className: 'vjs-next-video' |
17 | }) | 21 | }) as HTMLButtonElement |
18 | const nextIcon = videojsUntyped.dom.createEl('span', { | 22 | const nextIcon = videojs.dom.createEl('span', { |
19 | className: 'icon icon-next' | 23 | className: 'icon icon-next' |
20 | }) | 24 | }) |
21 | button.appendChild(nextIcon) | 25 | button.appendChild(nextIcon) |
@@ -26,11 +30,8 @@ class NextVideoButton extends Button { | |||
26 | } | 30 | } |
27 | 31 | ||
28 | handleClick () { | 32 | handleClick () { |
29 | this.options_.handler() | 33 | this.nextVideoButtonOptions.handler() |
30 | } | 34 | } |
31 | |||
32 | } | 35 | } |
33 | 36 | ||
34 | NextVideoButton.prototype.controlText_ = 'Next video' | 37 | videojs.registerComponent('NextVideoButton', NextVideoButton) |
35 | |||
36 | NextVideoButton.registerComponent('NextVideoButton', NextVideoButton) | ||
diff --git a/client/src/assets/player/videojs-components/p2p-info-button.ts b/client/src/assets/player/videojs-components/p2p-info-button.ts index 6424787b2..db6806fed 100644 --- a/client/src/assets/player/videojs-components/p2p-info-button.ts +++ b/client/src/assets/player/videojs-components/p2p-info-button.ts | |||
@@ -1,63 +1,64 @@ | |||
1 | import { PlayerNetworkInfo, VideoJSComponentInterface, videojsUntyped } from '../peertube-videojs-typings' | 1 | import { PlayerNetworkInfo } from '../peertube-videojs-typings' |
2 | import videojs from 'video.js' | ||
2 | import { bytes } from '../utils' | 3 | import { bytes } from '../utils' |
3 | 4 | ||
4 | const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button') | 5 | const Button = videojs.getComponent('Button') |
5 | class P2pInfoButton extends Button { | 6 | class P2pInfoButton extends Button { |
6 | 7 | ||
7 | createEl () { | 8 | createEl () { |
8 | const div = videojsUntyped.dom.createEl('div', { | 9 | const div = videojs.dom.createEl('div', { |
9 | className: 'vjs-peertube' | 10 | className: 'vjs-peertube' |
10 | }) | 11 | }) |
11 | const subDivWebtorrent = videojsUntyped.dom.createEl('div', { | 12 | const subDivWebtorrent = videojs.dom.createEl('div', { |
12 | className: 'vjs-peertube-hidden' // Hide the stats before we get the info | 13 | className: 'vjs-peertube-hidden' // Hide the stats before we get the info |
13 | }) | 14 | }) as HTMLDivElement |
14 | div.appendChild(subDivWebtorrent) | 15 | div.appendChild(subDivWebtorrent) |
15 | 16 | ||
16 | const downloadIcon = videojsUntyped.dom.createEl('span', { | 17 | const downloadIcon = videojs.dom.createEl('span', { |
17 | className: 'icon icon-download' | 18 | className: 'icon icon-download' |
18 | }) | 19 | }) |
19 | subDivWebtorrent.appendChild(downloadIcon) | 20 | subDivWebtorrent.appendChild(downloadIcon) |
20 | 21 | ||
21 | const downloadSpeedText = videojsUntyped.dom.createEl('span', { | 22 | const downloadSpeedText = videojs.dom.createEl('span', { |
22 | className: 'download-speed-text' | 23 | className: 'download-speed-text' |
23 | }) | 24 | }) |
24 | const downloadSpeedNumber = videojsUntyped.dom.createEl('span', { | 25 | const downloadSpeedNumber = videojs.dom.createEl('span', { |
25 | className: 'download-speed-number' | 26 | className: 'download-speed-number' |
26 | }) | 27 | }) |
27 | const downloadSpeedUnit = videojsUntyped.dom.createEl('span') | 28 | const downloadSpeedUnit = videojs.dom.createEl('span') |
28 | downloadSpeedText.appendChild(downloadSpeedNumber) | 29 | downloadSpeedText.appendChild(downloadSpeedNumber) |
29 | downloadSpeedText.appendChild(downloadSpeedUnit) | 30 | downloadSpeedText.appendChild(downloadSpeedUnit) |
30 | subDivWebtorrent.appendChild(downloadSpeedText) | 31 | subDivWebtorrent.appendChild(downloadSpeedText) |
31 | 32 | ||
32 | const uploadIcon = videojsUntyped.dom.createEl('span', { | 33 | const uploadIcon = videojs.dom.createEl('span', { |
33 | className: 'icon icon-upload' | 34 | className: 'icon icon-upload' |
34 | }) | 35 | }) |
35 | subDivWebtorrent.appendChild(uploadIcon) | 36 | subDivWebtorrent.appendChild(uploadIcon) |
36 | 37 | ||
37 | const uploadSpeedText = videojsUntyped.dom.createEl('span', { | 38 | const uploadSpeedText = videojs.dom.createEl('span', { |
38 | className: 'upload-speed-text' | 39 | className: 'upload-speed-text' |
39 | }) | 40 | }) |
40 | const uploadSpeedNumber = videojsUntyped.dom.createEl('span', { | 41 | const uploadSpeedNumber = videojs.dom.createEl('span', { |
41 | className: 'upload-speed-number' | 42 | className: 'upload-speed-number' |
42 | }) | 43 | }) |
43 | const uploadSpeedUnit = videojsUntyped.dom.createEl('span') | 44 | const uploadSpeedUnit = videojs.dom.createEl('span') |
44 | uploadSpeedText.appendChild(uploadSpeedNumber) | 45 | uploadSpeedText.appendChild(uploadSpeedNumber) |
45 | uploadSpeedText.appendChild(uploadSpeedUnit) | 46 | uploadSpeedText.appendChild(uploadSpeedUnit) |
46 | subDivWebtorrent.appendChild(uploadSpeedText) | 47 | subDivWebtorrent.appendChild(uploadSpeedText) |
47 | 48 | ||
48 | const peersText = videojsUntyped.dom.createEl('span', { | 49 | const peersText = videojs.dom.createEl('span', { |
49 | className: 'peers-text' | 50 | className: 'peers-text' |
50 | }) | 51 | }) |
51 | const peersNumber = videojsUntyped.dom.createEl('span', { | 52 | const peersNumber = videojs.dom.createEl('span', { |
52 | className: 'peers-number' | 53 | className: 'peers-number' |
53 | }) | 54 | }) |
54 | subDivWebtorrent.appendChild(peersNumber) | 55 | subDivWebtorrent.appendChild(peersNumber) |
55 | subDivWebtorrent.appendChild(peersText) | 56 | subDivWebtorrent.appendChild(peersText) |
56 | 57 | ||
57 | const subDivHttp = videojsUntyped.dom.createEl('div', { | 58 | const subDivHttp = videojs.dom.createEl('div', { |
58 | className: 'vjs-peertube-hidden' | 59 | className: 'vjs-peertube-hidden' |
59 | }) | 60 | }) |
60 | const subDivHttpText = videojsUntyped.dom.createEl('span', { | 61 | const subDivHttpText = videojs.dom.createEl('span', { |
61 | className: 'http-fallback', | 62 | className: 'http-fallback', |
62 | textContent: 'HTTP' | 63 | textContent: 'HTTP' |
63 | }) | 64 | }) |
@@ -83,8 +84,8 @@ class P2pInfoButton extends Button { | |||
83 | const totalUploaded = bytes(p2pStats.uploaded + httpStats.uploaded) | 84 | const totalUploaded = bytes(p2pStats.uploaded + httpStats.uploaded) |
84 | const numPeers = p2pStats.numPeers | 85 | const numPeers = p2pStats.numPeers |
85 | 86 | ||
86 | subDivWebtorrent.title = this.player_.localize('Total downloaded: ') + totalDownloaded.join(' ') + '\n' + | 87 | subDivWebtorrent.title = this.player().localize('Total downloaded: ') + totalDownloaded.join(' ') + '\n' + |
87 | this.player_.localize('Total uploaded: ' + totalUploaded.join(' ')) | 88 | this.player().localize('Total uploaded: ' + totalUploaded.join(' ')) |
88 | 89 | ||
89 | downloadSpeedNumber.textContent = downloadSpeed[ 0 ] | 90 | downloadSpeedNumber.textContent = downloadSpeed[ 0 ] |
90 | downloadSpeedUnit.textContent = ' ' + downloadSpeed[ 1 ] | 91 | downloadSpeedUnit.textContent = ' ' + downloadSpeed[ 1 ] |
@@ -92,14 +93,15 @@ class P2pInfoButton extends Button { | |||
92 | uploadSpeedNumber.textContent = uploadSpeed[ 0 ] | 93 | uploadSpeedNumber.textContent = uploadSpeed[ 0 ] |
93 | uploadSpeedUnit.textContent = ' ' + uploadSpeed[ 1 ] | 94 | uploadSpeedUnit.textContent = ' ' + uploadSpeed[ 1 ] |
94 | 95 | ||
95 | peersNumber.textContent = numPeers | 96 | peersNumber.textContent = numPeers.toString() |
96 | peersText.textContent = ' ' + (numPeers > 1 ? this.player_.localize('peers') : this.player_.localize('peer')) | 97 | peersText.textContent = ' ' + (numPeers > 1 ? this.player().localize('peers') : this.player_.localize('peer')) |
97 | 98 | ||
98 | subDivHttp.className = 'vjs-peertube-hidden' | 99 | subDivHttp.className = 'vjs-peertube-hidden' |
99 | subDivWebtorrent.className = 'vjs-peertube-displayed' | 100 | subDivWebtorrent.className = 'vjs-peertube-displayed' |
100 | }) | 101 | }) |
101 | 102 | ||
102 | return div | 103 | return div as HTMLButtonElement |
103 | } | 104 | } |
104 | } | 105 | } |
105 | Button.registerComponent('P2PInfoButton', P2pInfoButton) | 106 | |
107 | videojs.registerComponent('P2PInfoButton', P2pInfoButton) | ||
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 4d0ea37f5..0db9762a5 100644 --- a/client/src/assets/player/videojs-components/peertube-link-button.ts +++ b/client/src/assets/player/videojs-components/peertube-link-button.ts | |||
@@ -1,13 +1,10 @@ | |||
1 | import { VideoJSComponentInterface, videojsUntyped } from '../peertube-videojs-typings' | ||
2 | import { buildVideoLink } from '../utils' | 1 | import { buildVideoLink } from '../utils' |
3 | // FIXME: something weird with our path definition in tsconfig and typings | 2 | import videojs, { VideoJsPlayer } from 'video.js' |
4 | // @ts-ignore | ||
5 | import { Player } from 'video.js' | ||
6 | 3 | ||
7 | const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button') | 4 | const Button = videojs.getComponent('Button') |
8 | class PeerTubeLinkButton extends Button { | 5 | class PeerTubeLinkButton extends Button { |
9 | 6 | ||
10 | constructor (player: Player, options: any) { | 7 | constructor (player: VideoJsPlayer, options?: videojs.ComponentOptions) { |
11 | super(player, options) | 8 | super(player, options) |
12 | } | 9 | } |
13 | 10 | ||
@@ -20,21 +17,22 @@ class PeerTubeLinkButton extends Button { | |||
20 | } | 17 | } |
21 | 18 | ||
22 | handleClick () { | 19 | handleClick () { |
23 | this.player_.pause() | 20 | this.player().pause() |
24 | } | 21 | } |
25 | 22 | ||
26 | private buildElement () { | 23 | private buildElement () { |
27 | const el = videojsUntyped.dom.createEl('a', { | 24 | const el = videojs.dom.createEl('a', { |
28 | href: buildVideoLink(), | 25 | href: buildVideoLink(), |
29 | innerHTML: 'PeerTube', | 26 | innerHTML: 'PeerTube', |
30 | title: this.player_.localize('Go to the video page'), | 27 | title: this.player().localize('Go to the video page'), |
31 | className: 'vjs-peertube-link', | 28 | className: 'vjs-peertube-link', |
32 | target: '_blank' | 29 | target: '_blank' |
33 | }) | 30 | }) |
34 | 31 | ||
35 | el.addEventListener('mouseenter', () => this.updateHref()) | 32 | el.addEventListener('mouseenter', () => this.updateHref()) |
36 | 33 | ||
37 | return el | 34 | return el as HTMLButtonElement |
38 | } | 35 | } |
39 | } | 36 | } |
40 | Button.registerComponent('PeerTubeLinkButton', PeerTubeLinkButton) | 37 | |
38 | videojs.registerComponent('PeerTubeLinkButton', PeerTubeLinkButton) | ||
diff --git a/client/src/assets/player/videojs-components/peertube-load-progress-bar.ts b/client/src/assets/player/videojs-components/peertube-load-progress-bar.ts index b594fc1c5..8168e8f2d 100644 --- a/client/src/assets/player/videojs-components/peertube-load-progress-bar.ts +++ b/client/src/assets/player/videojs-components/peertube-load-progress-bar.ts | |||
@@ -1,16 +1,12 @@ | |||
1 | import { VideoJSComponentInterface, videojsUntyped } from '../peertube-videojs-typings' | 1 | import videojs, { VideoJsPlayer } from 'video.js' |
2 | // FIXME: something weird with our path definition in tsconfig and typings | ||
3 | // @ts-ignore | ||
4 | import { Player } from 'video.js' | ||
5 | 2 | ||
6 | const Component: VideoJSComponentInterface = videojsUntyped.getComponent('Component') | 3 | const Component = videojs.getComponent('Component') |
7 | 4 | ||
8 | class PeerTubeLoadProgressBar extends Component { | 5 | class PeerTubeLoadProgressBar extends Component { |
9 | partEls_: any[] | ||
10 | 6 | ||
11 | constructor (player: Player, options: any) { | 7 | constructor (player: VideoJsPlayer, options?: videojs.ComponentOptions) { |
12 | super(player, options) | 8 | super(player, options) |
13 | this.partEls_ = [] | 9 | |
14 | this.on(player, 'progress', this.update) | 10 | this.on(player, 'progress', this.update) |
15 | } | 11 | } |
16 | 12 | ||
@@ -22,8 +18,6 @@ class PeerTubeLoadProgressBar extends Component { | |||
22 | } | 18 | } |
23 | 19 | ||
24 | dispose () { | 20 | dispose () { |
25 | this.partEls_ = null | ||
26 | |||
27 | super.dispose() | 21 | super.dispose() |
28 | } | 22 | } |
29 | 23 | ||
@@ -31,7 +25,8 @@ class PeerTubeLoadProgressBar extends Component { | |||
31 | const torrent = this.player().webtorrent().getTorrent() | 25 | const torrent = this.player().webtorrent().getTorrent() |
32 | if (!torrent) return | 26 | if (!torrent) return |
33 | 27 | ||
34 | this.el_.style.width = (torrent.progress * 100) + '%' | 28 | // FIXME: typings |
29 | (this.el() as HTMLElement).style.width = (torrent.progress * 100) + '%' | ||
35 | } | 30 | } |
36 | 31 | ||
37 | } | 32 | } |
diff --git a/client/src/assets/player/videojs-components/resolution-menu-button.ts b/client/src/assets/player/videojs-components/resolution-menu-button.ts index 2de3ece19..0fa6272e7 100644 --- a/client/src/assets/player/videojs-components/resolution-menu-button.ts +++ b/client/src/assets/player/videojs-components/resolution-menu-button.ts | |||
@@ -1,22 +1,19 @@ | |||
1 | // FIXME: something weird with our path definition in tsconfig and typings | 1 | import videojs, { VideoJsPlayer } from 'video.js' |
2 | // @ts-ignore | ||
3 | import { Player } from 'video.js' | ||
4 | 2 | ||
5 | import { LoadedQualityData, VideoJSComponentInterface, videojsUntyped } from '../peertube-videojs-typings' | 3 | import { LoadedQualityData } from '../peertube-videojs-typings' |
6 | import { ResolutionMenuItem } from './resolution-menu-item' | 4 | import { ResolutionMenuItem } from './resolution-menu-item' |
7 | 5 | ||
8 | const Menu: VideoJSComponentInterface = videojsUntyped.getComponent('Menu') | 6 | const Menu = videojs.getComponent('Menu') |
9 | const MenuButton: VideoJSComponentInterface = videojsUntyped.getComponent('MenuButton') | 7 | const MenuButton = videojs.getComponent('MenuButton') |
10 | class ResolutionMenuButton extends MenuButton { | 8 | class ResolutionMenuButton extends MenuButton { |
11 | label: HTMLElement | 9 | labelEl_: HTMLElement |
12 | labelEl_: any | ||
13 | player: Player | ||
14 | 10 | ||
15 | constructor (player: Player, options: any) { | 11 | constructor (player: VideoJsPlayer, options?: videojs.MenuButtonOptions) { |
16 | super(player, options) | 12 | super(player, options) |
17 | this.player = player | ||
18 | 13 | ||
19 | player.tech_.on('loadedqualitydata', (e: any, data: any) => this.buildQualities(data)) | 14 | this.controlText('Quality') |
15 | |||
16 | player.tech(true).on('loadedqualitydata', (e: any, data: any) => this.buildQualities(data)) | ||
20 | 17 | ||
21 | player.peertube().on('resolutionChange', () => setTimeout(() => this.trigger('updateLabel'), 0)) | 18 | player.peertube().on('resolutionChange', () => setTimeout(() => this.trigger('updateLabel'), 0)) |
22 | } | 19 | } |
@@ -24,9 +21,9 @@ class ResolutionMenuButton extends MenuButton { | |||
24 | createEl () { | 21 | createEl () { |
25 | const el = super.createEl() | 22 | const el = super.createEl() |
26 | 23 | ||
27 | this.labelEl_ = videojsUntyped.dom.createEl('div', { | 24 | this.labelEl_ = videojs.dom.createEl('div', { |
28 | className: 'vjs-resolution-value' | 25 | className: 'vjs-resolution-value' |
29 | }) | 26 | }) as HTMLElement |
30 | 27 | ||
31 | el.appendChild(this.labelEl_) | 28 | el.appendChild(this.labelEl_) |
32 | 29 | ||
@@ -55,7 +52,7 @@ class ResolutionMenuButton extends MenuButton { | |||
55 | 52 | ||
56 | for (const child of children) { | 53 | for (const child of children) { |
57 | if (component !== child) { | 54 | if (component !== child) { |
58 | child.selected(false) | 55 | (child as videojs.MenuItem).selected(false) |
59 | } | 56 | } |
60 | } | 57 | } |
61 | }) | 58 | }) |
@@ -76,7 +73,7 @@ class ResolutionMenuButton extends MenuButton { | |||
76 | if (d.id === -1) continue | 73 | if (d.id === -1) continue |
77 | 74 | ||
78 | const label = d.label === '0p' | 75 | const label = d.label === '0p' |
79 | ? this.player.localize('Audio-only') | 76 | ? this.player().localize('Audio-only') |
80 | : d.label | 77 | : d.label |
81 | 78 | ||
82 | this.menu.addChild(new ResolutionMenuItem( | 79 | this.menu.addChild(new ResolutionMenuItem( |
@@ -110,6 +107,5 @@ class ResolutionMenuButton extends MenuButton { | |||
110 | this.trigger('menuChanged') | 107 | this.trigger('menuChanged') |
111 | } | 108 | } |
112 | } | 109 | } |
113 | ResolutionMenuButton.prototype.controlText_ = 'Quality' | ||
114 | 110 | ||
115 | MenuButton.registerComponent('ResolutionMenuButton', ResolutionMenuButton) | 111 | videojs.registerComponent('ResolutionMenuButton', ResolutionMenuButton) |
diff --git a/client/src/assets/player/videojs-components/resolution-menu-item.ts b/client/src/assets/player/videojs-components/resolution-menu-item.ts index 6c42fefd2..b039c4572 100644 --- a/client/src/assets/player/videojs-components/resolution-menu-item.ts +++ b/client/src/assets/player/videojs-components/resolution-menu-item.ts | |||
@@ -1,12 +1,16 @@ | |||
1 | // FIXME: something weird with our path definition in tsconfig and typings | 1 | import videojs, { VideoJsPlayer } from 'video.js' |
2 | // @ts-ignore | 2 | import { AutoResolutionUpdateData, ResolutionUpdateData } from '../peertube-videojs-typings' |
3 | import { Player } from 'video.js' | ||
4 | 3 | ||
5 | import { AutoResolutionUpdateData, ResolutionUpdateData, VideoJSComponentInterface, videojsUntyped } from '../peertube-videojs-typings' | 4 | const MenuItem = videojs.getComponent('MenuItem') |
5 | |||
6 | export interface ResolutionMenuItemOptions extends videojs.MenuItemOptions { | ||
7 | labels?: { [id: number]: string } | ||
8 | id: number | ||
9 | callback: Function | ||
10 | } | ||
6 | 11 | ||
7 | const MenuItem: VideoJSComponentInterface = videojsUntyped.getComponent('MenuItem') | ||
8 | class ResolutionMenuItem extends MenuItem { | 12 | class ResolutionMenuItem extends MenuItem { |
9 | private readonly id: number | 13 | private readonly resolutionId: number |
10 | private readonly label: string | 14 | private readonly label: string |
11 | // Only used for the automatic item | 15 | // Only used for the automatic item |
12 | private readonly labels: { [id: number]: string } | 16 | private readonly labels: { [id: number]: string } |
@@ -15,7 +19,7 @@ class ResolutionMenuItem extends MenuItem { | |||
15 | private autoResolutionPossible: boolean | 19 | private autoResolutionPossible: boolean |
16 | private currentResolutionLabel: string | 20 | private currentResolutionLabel: string |
17 | 21 | ||
18 | constructor (player: Player, options: any) { | 22 | constructor (player: VideoJsPlayer, options?: ResolutionMenuItemOptions) { |
19 | options.selectable = true | 23 | options.selectable = true |
20 | 24 | ||
21 | super(player, options) | 25 | super(player, options) |
@@ -23,40 +27,40 @@ class ResolutionMenuItem extends MenuItem { | |||
23 | this.autoResolutionPossible = true | 27 | this.autoResolutionPossible = true |
24 | this.currentResolutionLabel = '' | 28 | this.currentResolutionLabel = '' |
25 | 29 | ||
30 | this.resolutionId = options.id | ||
26 | this.label = options.label | 31 | this.label = options.label |
27 | this.labels = options.labels | 32 | this.labels = options.labels |
28 | this.id = options.id | ||
29 | this.callback = options.callback | 33 | this.callback = options.callback |
30 | 34 | ||
31 | player.peertube().on('resolutionChange', (_: any, data: ResolutionUpdateData) => this.updateSelection(data)) | 35 | player.peertube().on('resolutionChange', (_: any, data: ResolutionUpdateData) => this.updateSelection(data)) |
32 | 36 | ||
33 | // We only want to disable the "Auto" item | 37 | // We only want to disable the "Auto" item |
34 | if (this.id === -1) { | 38 | if (this.resolutionId === -1) { |
35 | player.peertube().on('autoResolutionChange', (_: any, data: AutoResolutionUpdateData) => this.updateAutoResolution(data)) | 39 | player.peertube().on('autoResolutionChange', (_: any, data: AutoResolutionUpdateData) => this.updateAutoResolution(data)) |
36 | } | 40 | } |
37 | } | 41 | } |
38 | 42 | ||
39 | handleClick (event: any) { | 43 | handleClick (event: any) { |
40 | // Auto button disabled? | 44 | // Auto button disabled? |
41 | if (this.autoResolutionPossible === false && this.id === -1) return | 45 | if (this.autoResolutionPossible === false && this.resolutionId === -1) return |
42 | 46 | ||
43 | super.handleClick(event) | 47 | super.handleClick(event) |
44 | 48 | ||
45 | this.callback(this.id, 'video') | 49 | this.callback(this.resolutionId, 'video') |
46 | } | 50 | } |
47 | 51 | ||
48 | updateSelection (data: ResolutionUpdateData) { | 52 | updateSelection (data: ResolutionUpdateData) { |
49 | if (this.id === -1) { | 53 | if (this.resolutionId === -1) { |
50 | this.currentResolutionLabel = this.labels[data.id] | 54 | this.currentResolutionLabel = this.labels[data.id] |
51 | } | 55 | } |
52 | 56 | ||
53 | // Automatic resolution only | 57 | // Automatic resolution only |
54 | if (data.auto === true) { | 58 | if (data.auto === true) { |
55 | this.selected(this.id === -1) | 59 | this.selected(this.resolutionId === -1) |
56 | return | 60 | return |
57 | } | 61 | } |
58 | 62 | ||
59 | this.selected(this.id === data.id) | 63 | this.selected(this.resolutionId === data.id) |
60 | } | 64 | } |
61 | 65 | ||
62 | updateAutoResolution (data: AutoResolutionUpdateData) { | 66 | updateAutoResolution (data: AutoResolutionUpdateData) { |
@@ -71,13 +75,13 @@ class ResolutionMenuItem extends MenuItem { | |||
71 | } | 75 | } |
72 | 76 | ||
73 | getLabel () { | 77 | getLabel () { |
74 | if (this.id === -1) { | 78 | if (this.resolutionId === -1) { |
75 | return this.label + ' <small>' + this.currentResolutionLabel + '</small>' | 79 | return this.label + ' <small>' + this.currentResolutionLabel + '</small>' |
76 | } | 80 | } |
77 | 81 | ||
78 | return this.label | 82 | return this.label |
79 | } | 83 | } |
80 | } | 84 | } |
81 | MenuItem.registerComponent('ResolutionMenuItem', ResolutionMenuItem) | 85 | videojs.registerComponent('ResolutionMenuItem', ResolutionMenuItem) |
82 | 86 | ||
83 | export { ResolutionMenuItem } | 87 | export { ResolutionMenuItem } |
diff --git a/client/src/assets/player/videojs-components/settings-dialog.ts b/client/src/assets/player/videojs-components/settings-dialog.ts new file mode 100644 index 000000000..dd0b1e472 --- /dev/null +++ b/client/src/assets/player/videojs-components/settings-dialog.ts | |||
@@ -0,0 +1,37 @@ | |||
1 | import videojs, { VideoJsPlayer } from 'video.js' | ||
2 | |||
3 | const Component = videojs.getComponent('Component') | ||
4 | |||
5 | class SettingsDialog extends Component { | ||
6 | constructor (player: VideoJsPlayer) { | ||
7 | super(player) | ||
8 | |||
9 | this.hide() | ||
10 | } | ||
11 | |||
12 | /** | ||
13 | * Create the component's DOM element | ||
14 | * | ||
15 | * @return {Element} | ||
16 | * @method createEl | ||
17 | */ | ||
18 | createEl () { | ||
19 | const uniqueId = this.id() | ||
20 | const dialogLabelId = 'TTsettingsDialogLabel-' + uniqueId | ||
21 | const dialogDescriptionId = 'TTsettingsDialogDescription-' + uniqueId | ||
22 | |||
23 | return super.createEl('div', { | ||
24 | className: 'vjs-settings-dialog vjs-modal-overlay', | ||
25 | innerHTML: '', | ||
26 | tabIndex: -1 | ||
27 | }, { | ||
28 | 'role': 'dialog', | ||
29 | 'aria-labelledby': dialogLabelId, | ||
30 | 'aria-describedby': dialogDescriptionId | ||
31 | }) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | Component.registerComponent('SettingsDialog', SettingsDialog) | ||
36 | |||
37 | export { SettingsDialog } | ||
diff --git a/client/src/assets/player/videojs-components/settings-menu-button.ts b/client/src/assets/player/videojs-components/settings-menu-button.ts index b700f4be6..eae628e7d 100644 --- a/client/src/assets/player/videojs-components/settings-menu-button.ts +++ b/client/src/assets/player/videojs-components/settings-menu-button.ts | |||
@@ -1,43 +1,52 @@ | |||
1 | // Author: Yanko Shterev | 1 | // Thanks to Yanko Shterev: https://github.com/yshterev/videojs-settings-menu |
2 | // Thanks https://github.com/yshterev/videojs-settings-menu | ||
3 | |||
4 | // FIXME: something weird with our path definition in tsconfig and typings | ||
5 | // @ts-ignore | ||
6 | import * as videojs from 'video.js' | ||
7 | |||
8 | import { SettingsMenuItem } from './settings-menu-item' | 2 | import { SettingsMenuItem } from './settings-menu-item' |
9 | import { VideoJSComponentInterface, videojsUntyped } from '../peertube-videojs-typings' | ||
10 | import { toTitleCase } from '../utils' | 3 | import { toTitleCase } from '../utils' |
4 | import videojs, { VideoJsPlayer } from 'video.js' | ||
5 | |||
6 | import { SettingsDialog } from './settings-dialog' | ||
7 | import { SettingsPanel } from './settings-panel' | ||
8 | import { SettingsPanelChild } from './settings-panel-child' | ||
11 | 9 | ||
12 | const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button') | 10 | const Button = videojs.getComponent('Button') |
13 | const Menu: VideoJSComponentInterface = videojsUntyped.getComponent('Menu') | 11 | const Menu = videojs.getComponent('Menu') |
14 | const Component: VideoJSComponentInterface = videojsUntyped.getComponent('Component') | 12 | const Component = videojs.getComponent('Component') |
13 | |||
14 | export interface SettingsButtonOptions extends videojs.ComponentOptions { | ||
15 | entries: any[] | ||
16 | setup?: { | ||
17 | maxHeightOffset: number | ||
18 | } | ||
19 | } | ||
15 | 20 | ||
16 | class SettingsButton extends Button { | 21 | class SettingsButton extends Button { |
17 | playerComponent = videojs.Player | 22 | dialog: SettingsDialog |
18 | dialog: any | 23 | dialogEl: HTMLElement |
19 | dialogEl: any | 24 | menu: videojs.Menu |
20 | menu: any | 25 | panel: SettingsPanel |
21 | panel: any | 26 | panelChild: SettingsPanelChild |
22 | panelChild: any | 27 | |
23 | 28 | addSettingsItemHandler: typeof SettingsButton.prototype.onAddSettingsItem | |
24 | addSettingsItemHandler: Function | 29 | disposeSettingsItemHandler: typeof SettingsButton.prototype.onDisposeSettingsItem |
25 | disposeSettingsItemHandler: Function | 30 | playerClickHandler: typeof SettingsButton.prototype.onPlayerClick |
26 | playerClickHandler: Function | 31 | userInactiveHandler: typeof SettingsButton.prototype.onUserInactive |
27 | userInactiveHandler: Function | 32 | |
28 | 33 | private settingsButtonOptions: SettingsButtonOptions | |
29 | constructor (player: videojs.Player, options: any) { | 34 | |
35 | constructor (player: VideoJsPlayer, options?: SettingsButtonOptions) { | ||
30 | super(player, options) | 36 | super(player, options) |
31 | 37 | ||
32 | this.playerComponent = player | 38 | this.settingsButtonOptions = options |
33 | this.dialog = this.playerComponent.addChild('settingsDialog') | 39 | |
34 | this.dialogEl = this.dialog.el_ | 40 | this.controlText('Settings') |
41 | |||
42 | this.dialog = this.player().addChild('settingsDialog') | ||
43 | this.dialogEl = this.dialog.el() as HTMLElement | ||
35 | this.menu = null | 44 | this.menu = null |
36 | this.panel = this.dialog.addChild('settingsPanel') | 45 | this.panel = this.dialog.addChild('settingsPanel') |
37 | this.panelChild = this.panel.addChild('settingsPanelChild') | 46 | this.panelChild = this.panel.addChild('settingsPanelChild') |
38 | 47 | ||
39 | this.addClass('vjs-settings') | 48 | this.addClass('vjs-settings') |
40 | this.el_.setAttribute('aria-label', 'Settings Button') | 49 | this.el().setAttribute('aria-label', 'Settings Button') |
41 | 50 | ||
42 | // Event handlers | 51 | // Event handlers |
43 | this.addSettingsItemHandler = this.onAddSettingsItem.bind(this) | 52 | this.addSettingsItemHandler = this.onAddSettingsItem.bind(this) |
@@ -84,7 +93,7 @@ class SettingsButton extends Button { | |||
84 | 93 | ||
85 | this.hideDialog() | 94 | this.hideDialog() |
86 | 95 | ||
87 | if (this.options_.entries.length === 0) { | 96 | if (this.settingsButtonOptions.entries.length === 0) { |
88 | this.addClass('vjs-hidden') | 97 | this.addClass('vjs-hidden') |
89 | } | 98 | } |
90 | } | 99 | } |
@@ -103,10 +112,10 @@ class SettingsButton extends Button { | |||
103 | } | 112 | } |
104 | 113 | ||
105 | bindEvents () { | 114 | bindEvents () { |
106 | this.playerComponent.on('click', this.playerClickHandler) | 115 | this.player().on('click', this.playerClickHandler) |
107 | this.playerComponent.on('addsettingsitem', this.addSettingsItemHandler) | 116 | this.player().on('addsettingsitem', this.addSettingsItemHandler) |
108 | this.playerComponent.on('disposesettingsitem', this.disposeSettingsItemHandler) | 117 | this.player().on('disposesettingsitem', this.disposeSettingsItemHandler) |
109 | this.playerComponent.on('userinactive', this.userInactiveHandler) | 118 | this.player().on('userinactive', this.userInactiveHandler) |
110 | } | 119 | } |
111 | 120 | ||
112 | buildCSSClass () { | 121 | buildCSSClass () { |
@@ -122,9 +131,9 @@ class SettingsButton extends Button { | |||
122 | } | 131 | } |
123 | 132 | ||
124 | showDialog () { | 133 | showDialog () { |
125 | this.player_.peertube().onMenuOpen() | 134 | this.player().peertube().onMenuOpen(); |
126 | 135 | ||
127 | this.menu.el_.style.opacity = '1' | 136 | (this.menu.el() as HTMLElement).style.opacity = '1' |
128 | this.dialog.show() | 137 | this.dialog.show() |
129 | 138 | ||
130 | this.setDialogSize(this.getComponentSize(this.menu)) | 139 | this.setDialogSize(this.getComponentSize(this.menu)) |
@@ -134,23 +143,24 @@ class SettingsButton extends Button { | |||
134 | this.player_.peertube().onMenuClosed() | 143 | this.player_.peertube().onMenuClosed() |
135 | 144 | ||
136 | this.dialog.hide() | 145 | this.dialog.hide() |
137 | this.setDialogSize(this.getComponentSize(this.menu)) | 146 | this.setDialogSize(this.getComponentSize(this.menu)); |
138 | this.menu.el_.style.opacity = '1' | 147 | (this.menu.el() as HTMLElement).style.opacity = '1' |
139 | this.resetChildren() | 148 | this.resetChildren() |
140 | } | 149 | } |
141 | 150 | ||
142 | getComponentSize (element: any) { | 151 | getComponentSize (element: videojs.Component | HTMLElement) { |
143 | let width: number = null | 152 | let width: number = null |
144 | let height: number = null | 153 | let height: number = null |
145 | 154 | ||
146 | // Could be component or just DOM element | 155 | // Could be component or just DOM element |
147 | if (element instanceof Component) { | 156 | if (element instanceof Component) { |
148 | width = element.el_.offsetWidth | 157 | const el = element.el() as HTMLElement |
149 | height = element.el_.offsetHeight | 158 | |
159 | width = el.offsetWidth | ||
160 | height = el.offsetHeight; | ||
150 | 161 | ||
151 | // keep width/height as properties for direct use | 162 | (element as any).width = width; |
152 | element.width = width | 163 | (element as any).height = height |
153 | element.height = height | ||
154 | } else { | 164 | } else { |
155 | width = element.offsetWidth | 165 | width = element.offsetWidth |
156 | height = element.offsetHeight | 166 | height = element.offsetHeight |
@@ -164,15 +174,17 @@ class SettingsButton extends Button { | |||
164 | return | 174 | return |
165 | } | 175 | } |
166 | 176 | ||
167 | const offset = this.options_.setup.maxHeightOffset | 177 | const offset = this.settingsButtonOptions.setup.maxHeightOffset |
168 | const maxHeight = this.playerComponent.el_.offsetHeight - offset | 178 | const maxHeight = (this.player().el() as HTMLElement).offsetHeight - offset // FIXME: typings |
179 | |||
180 | const panelEl = this.panel.el() as HTMLElement | ||
169 | 181 | ||
170 | if (height > maxHeight) { | 182 | if (height > maxHeight) { |
171 | height = maxHeight | 183 | height = maxHeight |
172 | width += 17 | 184 | width += 17 |
173 | this.panel.el_.style.maxHeight = `${height}px` | 185 | panelEl.style.maxHeight = `${height}px` |
174 | } else if (this.panel.el_.style.maxHeight !== '') { | 186 | } else if (panelEl.style.maxHeight !== '') { |
175 | this.panel.el_.style.maxHeight = '' | 187 | panelEl.style.maxHeight = '' |
176 | } | 188 | } |
177 | 189 | ||
178 | this.dialogEl.style.width = `${width}px` | 190 | this.dialogEl.style.width = `${width}px` |
@@ -182,7 +194,7 @@ class SettingsButton extends Button { | |||
182 | buildMenu () { | 194 | buildMenu () { |
183 | this.menu = new Menu(this.player()) | 195 | this.menu = new Menu(this.player()) |
184 | this.menu.addClass('vjs-main-menu') | 196 | this.menu.addClass('vjs-main-menu') |
185 | const entries = this.options_.entries | 197 | const entries = this.settingsButtonOptions.entries |
186 | 198 | ||
187 | if (entries.length === 0) { | 199 | if (entries.length === 0) { |
188 | this.addClass('vjs-hidden') | 200 | this.addClass('vjs-hidden') |
@@ -191,7 +203,7 @@ class SettingsButton extends Button { | |||
191 | } | 203 | } |
192 | 204 | ||
193 | for (const entry of entries) { | 205 | for (const entry of entries) { |
194 | this.addMenuItem(entry, this.options_) | 206 | this.addMenuItem(entry, this.settingsButtonOptions) |
195 | } | 207 | } |
196 | 208 | ||
197 | this.panelChild.addChild(this.menu) | 209 | this.panelChild.addChild(this.menu) |
@@ -199,15 +211,17 @@ class SettingsButton extends Button { | |||
199 | 211 | ||
200 | addMenuItem (entry: any, options: any) { | 212 | addMenuItem (entry: any, options: any) { |
201 | const openSubMenu = function (this: any) { | 213 | const openSubMenu = function (this: any) { |
202 | if (videojsUntyped.dom.hasClass(this.el_, 'open')) { | 214 | if (videojs.dom.hasClass(this.el_, 'open')) { |
203 | videojsUntyped.dom.removeClass(this.el_, 'open') | 215 | videojs.dom.removeClass(this.el_, 'open') |
204 | } else { | 216 | } else { |
205 | videojsUntyped.dom.addClass(this.el_, 'open') | 217 | videojs.dom.addClass(this.el_, 'open') |
206 | } | 218 | } |
207 | } | 219 | } |
208 | 220 | ||
209 | options.name = toTitleCase(entry) | 221 | options.name = toTitleCase(entry) |
210 | const settingsMenuItem = new SettingsMenuItem(this.player(), options, entry, this as any) | 222 | |
223 | const newOptions = Object.assign({}, options, { entry, menuButton: this }) | ||
224 | const settingsMenuItem = new SettingsMenuItem(this.player(), newOptions) | ||
211 | 225 | ||
212 | this.menu.addChild(settingsMenuItem) | 226 | this.menu.addChild(settingsMenuItem) |
213 | 227 | ||
@@ -221,7 +235,7 @@ class SettingsButton extends Button { | |||
221 | 235 | ||
222 | resetChildren () { | 236 | resetChildren () { |
223 | for (const menuChild of this.menu.children()) { | 237 | for (const menuChild of this.menu.children()) { |
224 | menuChild.reset() | 238 | (menuChild as SettingsMenuItem).reset() |
225 | } | 239 | } |
226 | } | 240 | } |
227 | 241 | ||
@@ -230,75 +244,12 @@ class SettingsButton extends Button { | |||
230 | */ | 244 | */ |
231 | hideChildren () { | 245 | hideChildren () { |
232 | for (const menuChild of this.menu.children()) { | 246 | for (const menuChild of this.menu.children()) { |
233 | menuChild.hideSubMenu() | 247 | (menuChild as SettingsMenuItem).hideSubMenu() |
234 | } | 248 | } |
235 | } | 249 | } |
236 | 250 | ||
237 | } | 251 | } |
238 | 252 | ||
239 | class SettingsPanel extends Component { | ||
240 | constructor (player: videojs.Player, options: any) { | ||
241 | super(player, options) | ||
242 | } | ||
243 | |||
244 | createEl () { | ||
245 | return super.createEl('div', { | ||
246 | className: 'vjs-settings-panel', | ||
247 | innerHTML: '', | ||
248 | tabIndex: -1 | ||
249 | }) | ||
250 | } | ||
251 | } | ||
252 | |||
253 | class SettingsPanelChild extends Component { | ||
254 | constructor (player: videojs.Player, options: any) { | ||
255 | super(player, options) | ||
256 | } | ||
257 | |||
258 | createEl () { | ||
259 | return super.createEl('div', { | ||
260 | className: 'vjs-settings-panel-child', | ||
261 | innerHTML: '', | ||
262 | tabIndex: -1 | ||
263 | }) | ||
264 | } | ||
265 | } | ||
266 | |||
267 | class SettingsDialog extends Component { | ||
268 | constructor (player: videojs.Player, options: any) { | ||
269 | super(player, options) | ||
270 | this.hide() | ||
271 | } | ||
272 | |||
273 | /** | ||
274 | * Create the component's DOM element | ||
275 | * | ||
276 | * @return {Element} | ||
277 | * @method createEl | ||
278 | */ | ||
279 | createEl () { | ||
280 | const uniqueId = this.id_ | ||
281 | const dialogLabelId = 'TTsettingsDialogLabel-' + uniqueId | ||
282 | const dialogDescriptionId = 'TTsettingsDialogDescription-' + uniqueId | ||
283 | |||
284 | return super.createEl('div', { | ||
285 | className: 'vjs-settings-dialog vjs-modal-overlay', | ||
286 | innerHTML: '', | ||
287 | tabIndex: -1 | ||
288 | }, { | ||
289 | 'role': 'dialog', | ||
290 | 'aria-labelledby': dialogLabelId, | ||
291 | 'aria-describedby': dialogDescriptionId | ||
292 | }) | ||
293 | } | ||
294 | |||
295 | } | ||
296 | |||
297 | SettingsButton.prototype.controlText_ = 'Settings' | ||
298 | |||
299 | Component.registerComponent('SettingsButton', SettingsButton) | 253 | Component.registerComponent('SettingsButton', SettingsButton) |
300 | Component.registerComponent('SettingsDialog', SettingsDialog) | ||
301 | Component.registerComponent('SettingsPanel', SettingsPanel) | ||
302 | Component.registerComponent('SettingsPanelChild', SettingsPanelChild) | ||
303 | 254 | ||
304 | export { SettingsButton, SettingsDialog, SettingsPanel, SettingsPanelChild } | 255 | export { SettingsButton } |
diff --git a/client/src/assets/player/videojs-components/settings-menu-item.ts b/client/src/assets/player/videojs-components/settings-menu-item.ts index 84d394c0e..f5671f49d 100644 --- a/client/src/assets/player/videojs-components/settings-menu-item.ts +++ b/client/src/assets/player/videojs-components/settings-menu-item.ts | |||
@@ -1,57 +1,63 @@ | |||
1 | // Author: Yanko Shterev | 1 | // Thanks to Yanko Shterev: https://github.com/yshterev/videojs-settings-menu |
2 | // Thanks https://github.com/yshterev/videojs-settings-menu | ||
3 | |||
4 | // FIXME: something weird with our path definition in tsconfig and typings | ||
5 | // @ts-ignore | ||
6 | import * as videojs from 'video.js' | ||
7 | |||
8 | import { toTitleCase } from '../utils' | 2 | import { toTitleCase } from '../utils' |
9 | import { VideoJSComponentInterface, videojsUntyped } from '../peertube-videojs-typings' | 3 | import videojs, { VideoJsPlayer } from 'video.js' |
10 | 4 | import { SettingsButton } from './settings-menu-button' | |
11 | const MenuItem: VideoJSComponentInterface = videojsUntyped.getComponent('MenuItem') | 5 | import { SettingsDialog } from './settings-dialog' |
12 | const component: VideoJSComponentInterface = videojsUntyped.getComponent('Component') | 6 | import { SettingsPanel } from './settings-panel' |
7 | import { SettingsPanelChild } from './settings-panel-child' | ||
8 | |||
9 | const MenuItem = videojs.getComponent('MenuItem') | ||
10 | const component = videojs.getComponent('Component') | ||
11 | |||
12 | export interface SettingsMenuItemOptions extends videojs.MenuItemOptions { | ||
13 | entry: string | ||
14 | menuButton: SettingsButton | ||
15 | } | ||
13 | 16 | ||
14 | class SettingsMenuItem extends MenuItem { | 17 | class SettingsMenuItem extends MenuItem { |
15 | settingsButton: any | 18 | settingsButton: SettingsButton |
16 | dialog: any | 19 | dialog: SettingsDialog |
17 | mainMenu: any | 20 | mainMenu: videojs.Menu |
18 | panel: any | 21 | panel: SettingsPanel |
19 | panelChild: any | 22 | panelChild: SettingsPanelChild |
20 | panelChildEl: any | 23 | panelChildEl: HTMLElement |
21 | size: any | 24 | size: number[] |
22 | menuToLoad: string | 25 | menuToLoad: string |
23 | subMenu: any | 26 | subMenu: SettingsButton |
24 | 27 | ||
25 | submenuClickHandler: Function | 28 | submenuClickHandler: typeof SettingsMenuItem.prototype.onSubmenuClick |
26 | transitionEndHandler: Function | 29 | transitionEndHandler: typeof SettingsMenuItem.prototype.onTransitionEnd |
27 | 30 | ||
28 | settingsSubMenuTitleEl_: any | 31 | settingsSubMenuTitleEl_: HTMLElement |
29 | settingsSubMenuValueEl_: any | 32 | settingsSubMenuValueEl_: HTMLElement |
30 | settingsSubMenuEl_: any | 33 | settingsSubMenuEl_: HTMLElement |
31 | 34 | ||
32 | constructor (player: videojs.Player, options: any, entry: string, menuButton: VideoJSComponentInterface) { | 35 | constructor (player: VideoJsPlayer, options?: SettingsMenuItemOptions) { |
33 | super(player, options) | 36 | super(player, options) |
34 | 37 | ||
35 | this.settingsButton = menuButton | 38 | this.settingsButton = options.menuButton |
36 | this.dialog = this.settingsButton.dialog | 39 | this.dialog = this.settingsButton.dialog |
37 | this.mainMenu = this.settingsButton.menu | 40 | this.mainMenu = this.settingsButton.menu |
38 | this.panel = this.dialog.getChild('settingsPanel') | 41 | this.panel = this.dialog.getChild('settingsPanel') |
39 | this.panelChild = this.panel.getChild('settingsPanelChild') | 42 | this.panelChild = this.panel.getChild('settingsPanelChild') |
40 | this.panelChildEl = this.panelChild.el_ | 43 | this.panelChildEl = this.panelChild.el() as HTMLElement |
41 | 44 | ||
42 | this.size = null | 45 | this.size = null |
43 | 46 | ||
44 | // keep state of what menu type is loading next | 47 | // keep state of what menu type is loading next |
45 | this.menuToLoad = 'mainmenu' | 48 | this.menuToLoad = 'mainmenu' |
46 | 49 | ||
47 | const subMenuName = toTitleCase(entry) | 50 | const subMenuName = toTitleCase(options.entry) |
48 | const SubMenuComponent = videojsUntyped.getComponent(subMenuName) | 51 | const SubMenuComponent = videojs.getComponent(subMenuName) |
49 | 52 | ||
50 | if (!SubMenuComponent) { | 53 | if (!SubMenuComponent) { |
51 | throw new Error(`Component ${subMenuName} does not exist`) | 54 | throw new Error(`Component ${subMenuName} does not exist`) |
52 | } | 55 | } |
53 | this.subMenu = new SubMenuComponent(this.player(), options, menuButton, this) | 56 | |
54 | const subMenuClass = this.subMenu.buildCSSClass().split(' ')[0] | 57 | const newOptions = Object.assign({}, options, { entry: options.menuButton, menuButton: this }) |
58 | |||
59 | this.subMenu = new SubMenuComponent(this.player(), newOptions) as any // FIXME: typings | ||
60 | const subMenuClass = this.subMenu.buildCSSClass().split(' ')[ 0 ] | ||
55 | this.settingsSubMenuEl_.className += ' ' + subMenuClass | 61 | this.settingsSubMenuEl_.className += ' ' + subMenuClass |
56 | 62 | ||
57 | this.eventHandlers() | 63 | this.eventHandlers() |
@@ -72,7 +78,7 @@ class SettingsMenuItem extends MenuItem { | |||
72 | player.on('captionsChanged', () => { | 78 | player.on('captionsChanged', () => { |
73 | setTimeout(() => { | 79 | setTimeout(() => { |
74 | this.settingsSubMenuEl_.innerHTML = '' | 80 | this.settingsSubMenuEl_.innerHTML = '' |
75 | this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el_) | 81 | this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el()) |
76 | this.update() | 82 | this.update() |
77 | this.bindClickEvents() | 83 | this.bindClickEvents() |
78 | }, 0) | 84 | }, 0) |
@@ -119,27 +125,27 @@ class SettingsMenuItem extends MenuItem { | |||
119 | * @method createEl | 125 | * @method createEl |
120 | */ | 126 | */ |
121 | createEl () { | 127 | createEl () { |
122 | const el = videojsUntyped.dom.createEl('li', { | 128 | const el = videojs.dom.createEl('li', { |
123 | className: 'vjs-menu-item' | 129 | className: 'vjs-menu-item' |
124 | }) | 130 | }) |
125 | 131 | ||
126 | this.settingsSubMenuTitleEl_ = videojsUntyped.dom.createEl('div', { | 132 | this.settingsSubMenuTitleEl_ = videojs.dom.createEl('div', { |
127 | className: 'vjs-settings-sub-menu-title' | 133 | className: 'vjs-settings-sub-menu-title' |
128 | }) | 134 | }) as HTMLElement |
129 | 135 | ||
130 | el.appendChild(this.settingsSubMenuTitleEl_) | 136 | el.appendChild(this.settingsSubMenuTitleEl_) |
131 | 137 | ||
132 | this.settingsSubMenuValueEl_ = videojsUntyped.dom.createEl('div', { | 138 | this.settingsSubMenuValueEl_ = videojs.dom.createEl('div', { |
133 | className: 'vjs-settings-sub-menu-value' | 139 | className: 'vjs-settings-sub-menu-value' |
134 | }) | 140 | }) as HTMLElement |
135 | 141 | ||
136 | el.appendChild(this.settingsSubMenuValueEl_) | 142 | el.appendChild(this.settingsSubMenuValueEl_) |
137 | 143 | ||
138 | this.settingsSubMenuEl_ = videojsUntyped.dom.createEl('div', { | 144 | this.settingsSubMenuEl_ = videojs.dom.createEl('div', { |
139 | className: 'vjs-settings-sub-menu' | 145 | className: 'vjs-settings-sub-menu' |
140 | }) | 146 | }) as HTMLElement |
141 | 147 | ||
142 | return el | 148 | return el as HTMLLIElement |
143 | } | 149 | } |
144 | 150 | ||
145 | /** | 151 | /** |
@@ -147,17 +153,17 @@ class SettingsMenuItem extends MenuItem { | |||
147 | * | 153 | * |
148 | * @method handleClick | 154 | * @method handleClick |
149 | */ | 155 | */ |
150 | handleClick () { | 156 | handleClick (event: videojs.EventTarget.Event) { |
151 | this.menuToLoad = 'submenu' | 157 | this.menuToLoad = 'submenu' |
152 | // Remove open class to ensure only the open submenu gets this class | 158 | // Remove open class to ensure only the open submenu gets this class |
153 | videojsUntyped.dom.removeClass(this.el_, 'open') | 159 | videojs.dom.removeClass(this.el(), 'open') |
154 | 160 | ||
155 | super.handleClick() | 161 | super.handleClick(event); |
156 | 162 | ||
157 | this.mainMenu.el_.style.opacity = '0' | 163 | (this.mainMenu.el() as HTMLElement).style.opacity = '0' |
158 | // Whether to add or remove vjs-hidden class on the settingsSubMenuEl element | 164 | // Whether to add or remove vjs-hidden class on the settingsSubMenuEl element |
159 | if (videojsUntyped.dom.hasClass(this.settingsSubMenuEl_, 'vjs-hidden')) { | 165 | if (videojs.dom.hasClass(this.settingsSubMenuEl_, 'vjs-hidden')) { |
160 | videojsUntyped.dom.removeClass(this.settingsSubMenuEl_, 'vjs-hidden') | 166 | videojs.dom.removeClass(this.settingsSubMenuEl_, 'vjs-hidden') |
161 | 167 | ||
162 | // animation not played without timeout | 168 | // animation not played without timeout |
163 | setTimeout(() => { | 169 | setTimeout(() => { |
@@ -167,7 +173,7 @@ class SettingsMenuItem extends MenuItem { | |||
167 | 173 | ||
168 | this.settingsButton.setDialogSize(this.size) | 174 | this.settingsButton.setDialogSize(this.size) |
169 | } else { | 175 | } else { |
170 | videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') | 176 | videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') |
171 | } | 177 | } |
172 | } | 178 | } |
173 | 179 | ||
@@ -178,9 +184,9 @@ class SettingsMenuItem extends MenuItem { | |||
178 | */ | 184 | */ |
179 | createBackButton () { | 185 | createBackButton () { |
180 | const button = this.subMenu.menu.addChild('MenuItem', {}, 0) | 186 | const button = this.subMenu.menu.addChild('MenuItem', {}, 0) |
181 | button.name_ = 'BackButton' | 187 | |
182 | button.addClass('vjs-back-button') | 188 | button.addClass('vjs-back-button'); |
183 | button.el_.innerHTML = this.player_.localize(this.subMenu.controlText_) | 189 | (button.el() as HTMLElement).innerHTML = this.player().localize(this.subMenu.controlText()) |
184 | } | 190 | } |
185 | 191 | ||
186 | /** | 192 | /** |
@@ -189,17 +195,17 @@ class SettingsMenuItem extends MenuItem { | |||
189 | * @method PrefixedEvent | 195 | * @method PrefixedEvent |
190 | */ | 196 | */ |
191 | PrefixedEvent (element: any, type: any, callback: any, action = 'addEvent') { | 197 | PrefixedEvent (element: any, type: any, callback: any, action = 'addEvent') { |
192 | const prefix = ['webkit', 'moz', 'MS', 'o', ''] | 198 | const prefix = [ 'webkit', 'moz', 'MS', 'o', '' ] |
193 | 199 | ||
194 | for (let p = 0; p < prefix.length; p++) { | 200 | for (let p = 0; p < prefix.length; p++) { |
195 | if (!prefix[p]) { | 201 | if (!prefix[ p ]) { |
196 | type = type.toLowerCase() | 202 | type = type.toLowerCase() |
197 | } | 203 | } |
198 | 204 | ||
199 | if (action === 'addEvent') { | 205 | if (action === 'addEvent') { |
200 | element.addEventListener(prefix[p] + type, callback, false) | 206 | element.addEventListener(prefix[ p ] + type, callback, false) |
201 | } else if (action === 'removeEvent') { | 207 | } else if (action === 'removeEvent') { |
202 | element.removeEventListener(prefix[p] + type, callback, false) | 208 | element.removeEventListener(prefix[ p ] + type, callback, false) |
203 | } | 209 | } |
204 | } | 210 | } |
205 | } | 211 | } |
@@ -211,7 +217,7 @@ class SettingsMenuItem extends MenuItem { | |||
211 | 217 | ||
212 | if (this.menuToLoad === 'mainmenu') { | 218 | if (this.menuToLoad === 'mainmenu') { |
213 | // hide submenu | 219 | // hide submenu |
214 | videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') | 220 | videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') |
215 | 221 | ||
216 | // reset opacity to 0 | 222 | // reset opacity to 0 |
217 | this.settingsSubMenuEl_.style.opacity = '0' | 223 | this.settingsSubMenuEl_.style.opacity = '0' |
@@ -219,25 +225,27 @@ class SettingsMenuItem extends MenuItem { | |||
219 | } | 225 | } |
220 | 226 | ||
221 | reset () { | 227 | reset () { |
222 | videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') | 228 | videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') |
223 | this.settingsSubMenuEl_.style.opacity = '0' | 229 | this.settingsSubMenuEl_.style.opacity = '0' |
224 | this.setMargin() | 230 | this.setMargin() |
225 | } | 231 | } |
226 | 232 | ||
227 | loadMainMenu () { | 233 | loadMainMenu () { |
234 | const mainMenuEl = this.mainMenu.el() as HTMLElement | ||
228 | this.menuToLoad = 'mainmenu' | 235 | this.menuToLoad = 'mainmenu' |
229 | this.mainMenu.show() | 236 | this.mainMenu.show() |
230 | this.mainMenu.el_.style.opacity = '0' | 237 | mainMenuEl.style.opacity = '0' |
231 | 238 | ||
232 | // back button will always take you to main menu, so set dialog sizes | 239 | // back button will always take you to main menu, so set dialog sizes |
233 | this.settingsButton.setDialogSize([this.mainMenu.width, this.mainMenu.height]) | 240 | const mainMenuAny = this.mainMenu as any |
241 | this.settingsButton.setDialogSize([ mainMenuAny.width, mainMenuAny.height ]) | ||
234 | 242 | ||
235 | // animation not triggered without timeout (some async stuff ?!?) | 243 | // animation not triggered without timeout (some async stuff ?!?) |
236 | setTimeout(() => { | 244 | setTimeout(() => { |
237 | // animate margin and opacity before hiding the submenu | 245 | // animate margin and opacity before hiding the submenu |
238 | // this triggers CSS Transition event | 246 | // this triggers CSS Transition event |
239 | this.setMargin() | 247 | this.setMargin() |
240 | this.mainMenu.el_.style.opacity = '1' | 248 | mainMenuEl.style.opacity = '1' |
241 | }, 0) | 249 | }, 0) |
242 | } | 250 | } |
243 | 251 | ||
@@ -251,8 +259,8 @@ class SettingsMenuItem extends MenuItem { | |||
251 | this.update() | 259 | this.update() |
252 | }) | 260 | }) |
253 | 261 | ||
254 | this.settingsSubMenuTitleEl_.innerHTML = this.player_.localize(this.subMenu.controlText_) | 262 | this.settingsSubMenuTitleEl_.innerHTML = this.player().localize(this.subMenu.controlText()) |
255 | this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el_) | 263 | this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el()) |
256 | this.panelChildEl.appendChild(this.settingsSubMenuEl_) | 264 | this.panelChildEl.appendChild(this.settingsSubMenuEl_) |
257 | this.update() | 265 | this.update() |
258 | 266 | ||
@@ -283,7 +291,8 @@ class SettingsMenuItem extends MenuItem { | |||
283 | // or sets options_['selected'] on the selected playback rate. | 291 | // or sets options_['selected'] on the selected playback rate. |
284 | // Thus we get the submenu value based on the labelEl of playbackRateMenuButton | 292 | // Thus we get the submenu value based on the labelEl of playbackRateMenuButton |
285 | if (subMenu === 'PlaybackRateMenuButton') { | 293 | if (subMenu === 'PlaybackRateMenuButton') { |
286 | setTimeout(() => this.settingsSubMenuValueEl_.innerHTML = this.subMenu.labelEl_.innerHTML, 250) | 294 | const html = (this.subMenu as any).labelEl_.innerHTML |
295 | setTimeout(() => this.settingsSubMenuValueEl_.innerHTML = html, 250) | ||
287 | } else { | 296 | } else { |
288 | // Loop trough the submenu items to find the selected child | 297 | // Loop trough the submenu items to find the selected child |
289 | for (const subMenuItem of this.subMenu.menu.children_) { | 298 | for (const subMenuItem of this.subMenu.menu.children_) { |
@@ -292,13 +301,15 @@ class SettingsMenuItem extends MenuItem { | |||
292 | } | 301 | } |
293 | 302 | ||
294 | if (subMenuItem.hasClass('vjs-selected')) { | 303 | if (subMenuItem.hasClass('vjs-selected')) { |
304 | const subMenuItemUntyped = subMenuItem as any | ||
305 | |||
295 | // Prefer to use the function | 306 | // Prefer to use the function |
296 | if (typeof subMenuItem.getLabel === 'function') { | 307 | if (typeof subMenuItemUntyped.getLabel === 'function') { |
297 | this.settingsSubMenuValueEl_.innerHTML = subMenuItem.getLabel() | 308 | this.settingsSubMenuValueEl_.innerHTML = subMenuItemUntyped.getLabel() |
298 | break | 309 | break |
299 | } | 310 | } |
300 | 311 | ||
301 | this.settingsSubMenuValueEl_.innerHTML = subMenuItem.options_.label | 312 | this.settingsSubMenuValueEl_.innerHTML = subMenuItemUntyped.options_.label |
302 | } | 313 | } |
303 | } | 314 | } |
304 | } | 315 | } |
@@ -313,7 +324,7 @@ class SettingsMenuItem extends MenuItem { | |||
313 | if (!(item instanceof component)) { | 324 | if (!(item instanceof component)) { |
314 | continue | 325 | continue |
315 | } | 326 | } |
316 | item.on(['tap', 'click'], this.submenuClickHandler) | 327 | item.on([ 'tap', 'click' ], this.submenuClickHandler) |
317 | } | 328 | } |
318 | } | 329 | } |
319 | 330 | ||
@@ -321,11 +332,11 @@ class SettingsMenuItem extends MenuItem { | |||
321 | // if number of submenu items change dynamically more logic will be needed | 332 | // if number of submenu items change dynamically more logic will be needed |
322 | setSize () { | 333 | setSize () { |
323 | this.dialog.removeClass('vjs-hidden') | 334 | this.dialog.removeClass('vjs-hidden') |
324 | videojsUntyped.dom.removeClass(this.settingsSubMenuEl_, 'vjs-hidden') | 335 | videojs.dom.removeClass(this.settingsSubMenuEl_, 'vjs-hidden') |
325 | this.size = this.settingsButton.getComponentSize(this.settingsSubMenuEl_) | 336 | this.size = this.settingsButton.getComponentSize(this.settingsSubMenuEl_) |
326 | this.setMargin() | 337 | this.setMargin() |
327 | this.dialog.addClass('vjs-hidden') | 338 | this.dialog.addClass('vjs-hidden') |
328 | videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') | 339 | videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') |
329 | } | 340 | } |
330 | 341 | ||
331 | setMargin () { | 342 | setMargin () { |
@@ -341,19 +352,19 @@ class SettingsMenuItem extends MenuItem { | |||
341 | */ | 352 | */ |
342 | hideSubMenu () { | 353 | hideSubMenu () { |
343 | // after removing settings item this.el_ === null | 354 | // after removing settings item this.el_ === null |
344 | if (!this.el_) { | 355 | if (!this.el()) { |
345 | return | 356 | return |
346 | } | 357 | } |
347 | 358 | ||
348 | if (videojsUntyped.dom.hasClass(this.el_, 'open')) { | 359 | if (videojs.dom.hasClass(this.el(), 'open')) { |
349 | videojsUntyped.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') | 360 | videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden') |
350 | videojsUntyped.dom.removeClass(this.el_, 'open') | 361 | videojs.dom.removeClass(this.el(), 'open') |
351 | } | 362 | } |
352 | } | 363 | } |
353 | 364 | ||
354 | } | 365 | } |
355 | 366 | ||
356 | SettingsMenuItem.prototype.contentElType = 'button' | 367 | (SettingsMenuItem as any).prototype.contentElType = 'button' |
357 | videojsUntyped.registerComponent('SettingsMenuItem', SettingsMenuItem) | 368 | videojs.registerComponent('SettingsMenuItem', SettingsMenuItem) |
358 | 369 | ||
359 | export { SettingsMenuItem } | 370 | export { SettingsMenuItem } |
diff --git a/client/src/assets/player/videojs-components/settings-panel-child.ts b/client/src/assets/player/videojs-components/settings-panel-child.ts new file mode 100644 index 000000000..d12e8218a --- /dev/null +++ b/client/src/assets/player/videojs-components/settings-panel-child.ts | |||
@@ -0,0 +1,22 @@ | |||
1 | import videojs, { VideoJsPlayer } from 'video.js' | ||
2 | |||
3 | const Component = videojs.getComponent('Component') | ||
4 | |||
5 | class SettingsPanelChild extends Component { | ||
6 | |||
7 | constructor (player: VideoJsPlayer, options?: videojs.ComponentOptions) { | ||
8 | super(player, options) | ||
9 | } | ||
10 | |||
11 | createEl () { | ||
12 | return super.createEl('div', { | ||
13 | className: 'vjs-settings-panel-child', | ||
14 | innerHTML: '', | ||
15 | tabIndex: -1 | ||
16 | }) | ||
17 | } | ||
18 | } | ||
19 | |||
20 | Component.registerComponent('SettingsPanelChild', SettingsPanelChild) | ||
21 | |||
22 | export { SettingsPanelChild } | ||
diff --git a/client/src/assets/player/videojs-components/settings-panel.ts b/client/src/assets/player/videojs-components/settings-panel.ts new file mode 100644 index 000000000..2090abf45 --- /dev/null +++ b/client/src/assets/player/videojs-components/settings-panel.ts | |||
@@ -0,0 +1,22 @@ | |||
1 | import videojs, { VideoJsPlayer } from 'video.js' | ||
2 | |||
3 | const Component = videojs.getComponent('Component') | ||
4 | |||
5 | class SettingsPanel extends Component { | ||
6 | |||
7 | constructor (player: VideoJsPlayer, options?: videojs.ComponentOptions) { | ||
8 | super(player, options) | ||
9 | } | ||
10 | |||
11 | createEl () { | ||
12 | return super.createEl('div', { | ||
13 | className: 'vjs-settings-panel', | ||
14 | innerHTML: '', | ||
15 | tabIndex: -1 | ||
16 | }) | ||
17 | } | ||
18 | } | ||
19 | |||
20 | Component.registerComponent('SettingsPanel', SettingsPanel) | ||
21 | |||
22 | export { SettingsPanel } | ||
diff --git a/client/src/assets/player/videojs-components/theater-button.ts b/client/src/assets/player/videojs-components/theater-button.ts index bf383cf34..1c8c9f154 100644 --- a/client/src/assets/player/videojs-components/theater-button.ts +++ b/client/src/assets/player/videojs-components/theater-button.ts | |||
@@ -1,26 +1,24 @@ | |||
1 | // FIXME: something weird with our path definition in tsconfig and typings | 1 | import videojs, { VideoJsPlayer } from 'video.js' |
2 | // @ts-ignore | ||
3 | import * as videojs from 'video.js' | ||
4 | |||
5 | import { VideoJSComponentInterface, videojsUntyped } from '../peertube-videojs-typings' | ||
6 | import { saveTheaterInStore, getStoredTheater } from '../peertube-player-local-storage' | 2 | import { saveTheaterInStore, getStoredTheater } from '../peertube-player-local-storage' |
7 | 3 | ||
8 | const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button') | 4 | const Button = videojs.getComponent('Button') |
9 | class TheaterButton extends Button { | 5 | class TheaterButton extends Button { |
10 | 6 | ||
11 | private static readonly THEATER_MODE_CLASS = 'vjs-theater-enabled' | 7 | private static readonly THEATER_MODE_CLASS = 'vjs-theater-enabled' |
12 | 8 | ||
13 | constructor (player: videojs.Player, options: any) { | 9 | constructor (player: VideoJsPlayer, options: videojs.ComponentOptions) { |
14 | super(player, options) | 10 | super(player, options) |
15 | 11 | ||
16 | const enabled = getStoredTheater() | 12 | const enabled = getStoredTheater() |
17 | if (enabled === true) { | 13 | if (enabled === true) { |
18 | this.player_.addClass(TheaterButton.THEATER_MODE_CLASS) | 14 | this.player().addClass(TheaterButton.THEATER_MODE_CLASS) |
19 | 15 | ||
20 | this.handleTheaterChange() | 16 | this.handleTheaterChange() |
21 | } | 17 | } |
22 | 18 | ||
23 | this.player_.theaterEnabled = enabled | 19 | this.controlText('Theater mode') |
20 | |||
21 | this.player().theaterEnabled = enabled | ||
24 | } | 22 | } |
25 | 23 | ||
26 | buildCSSClass () { | 24 | buildCSSClass () { |
@@ -52,6 +50,4 @@ class TheaterButton extends Button { | |||
52 | } | 50 | } |
53 | } | 51 | } |
54 | 52 | ||
55 | TheaterButton.prototype.controlText_ = 'Theater mode' | 53 | videojs.registerComponent('TheaterButton', TheaterButton) |
56 | |||
57 | TheaterButton.registerComponent('TheaterButton', TheaterButton) | ||
diff --git a/client/src/assets/player/webtorrent/webtorrent-plugin.ts b/client/src/assets/player/webtorrent/webtorrent-plugin.ts index 35cf85c99..bf6b0a718 100644 --- a/client/src/assets/player/webtorrent/webtorrent-plugin.ts +++ b/client/src/assets/player/webtorrent/webtorrent-plugin.ts | |||
@@ -1,17 +1,15 @@ | |||
1 | // FIXME: something weird with our path definition in tsconfig and typings | 1 | import videojs, { VideoJsPlayer } from 'video.js' |
2 | // @ts-ignore | ||
3 | import * as videojs from 'video.js' | ||
4 | 2 | ||
5 | import * as WebTorrent from 'webtorrent' | 3 | import * as WebTorrent from 'webtorrent' |
6 | import { renderVideo } from './video-renderer' | 4 | import { renderVideo } from './video-renderer' |
7 | import { LoadedQualityData, PlayerNetworkInfo, VideoJSComponentInterface, WebtorrentPluginOptions } from '../peertube-videojs-typings' | 5 | import { LoadedQualityData, PlayerNetworkInfo, WebtorrentPluginOptions } from '../peertube-videojs-typings' |
8 | import { getRtcConfig, timeToInt, videoFileMaxByResolution, videoFileMinByResolution } from '../utils' | 6 | import { getRtcConfig, timeToInt, videoFileMaxByResolution, videoFileMinByResolution } from '../utils' |
9 | import { PeertubeChunkStore } from './peertube-chunk-store' | 7 | import { PeertubeChunkStore } from './peertube-chunk-store' |
10 | import { | 8 | import { |
11 | getAverageBandwidthInStore, | 9 | getAverageBandwidthInStore, |
12 | getStoredMute, | 10 | getStoredMute, |
13 | getStoredVolume, | ||
14 | getStoredP2PEnabled, | 11 | getStoredP2PEnabled, |
12 | getStoredVolume, | ||
15 | saveAverageBandwidth | 13 | saveAverageBandwidth |
16 | } from '../peertube-player-local-storage' | 14 | } from '../peertube-player-local-storage' |
17 | import { VideoFile } from '@shared/models' | 15 | import { VideoFile } from '@shared/models' |
@@ -24,14 +22,16 @@ type PlayOptions = { | |||
24 | delay?: number | 22 | delay?: number |
25 | } | 23 | } |
26 | 24 | ||
27 | const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') | 25 | const Plugin = videojs.getPlugin('plugin') |
26 | |||
28 | class WebTorrentPlugin extends Plugin { | 27 | class WebTorrentPlugin extends Plugin { |
28 | readonly videoFiles: VideoFile[] | ||
29 | |||
29 | private readonly playerElement: HTMLVideoElement | 30 | private readonly playerElement: HTMLVideoElement |
30 | 31 | ||
31 | private readonly autoplay: boolean = false | 32 | private readonly autoplay: boolean = false |
32 | private readonly startTime: number = 0 | 33 | private readonly startTime: number = 0 |
33 | private readonly savePlayerSrcFunction: Function | 34 | private readonly savePlayerSrcFunction: VideoJsPlayer['src'] |
34 | private readonly videoFiles: VideoFile[] | ||
35 | private readonly videoDuration: number | 35 | private readonly videoDuration: number |
36 | private readonly CONSTANTS = { | 36 | private readonly CONSTANTS = { |
37 | INFO_SCHEDULER: 1000, // Don't change this | 37 | INFO_SCHEDULER: 1000, // Don't change this |
@@ -49,7 +49,6 @@ class WebTorrentPlugin extends Plugin { | |||
49 | dht: false | 49 | dht: false |
50 | }) | 50 | }) |
51 | 51 | ||
52 | private player: any | ||
53 | private currentVideoFile: VideoFile | 52 | private currentVideoFile: VideoFile |
54 | private torrent: WebTorrent.Torrent | 53 | private torrent: WebTorrent.Torrent |
55 | 54 | ||
@@ -70,8 +69,8 @@ class WebTorrentPlugin extends Plugin { | |||
70 | 69 | ||
71 | private downloadSpeeds: number[] = [] | 70 | private downloadSpeeds: number[] = [] |
72 | 71 | ||
73 | constructor (player: videojs.Player, options: WebtorrentPluginOptions) { | 72 | constructor (player: VideoJsPlayer, options?: WebtorrentPluginOptions) { |
74 | super(player, options) | 73 | super(player) |
75 | 74 | ||
76 | this.startTime = timeToInt(options.startTime) | 75 | this.startTime = timeToInt(options.startTime) |
77 | 76 | ||
@@ -147,12 +146,12 @@ class WebTorrentPlugin extends Plugin { | |||
147 | } | 146 | } |
148 | 147 | ||
149 | // Do not display error to user because we will have multiple fallback | 148 | // Do not display error to user because we will have multiple fallback |
150 | this.disableErrorDisplay() | 149 | this.disableErrorDisplay(); |
151 | 150 | ||
152 | // Hack to "simulate" src link in video.js >= 6 | 151 | // Hack to "simulate" src link in video.js >= 6 |
153 | // Without this, we can't play the video after pausing it | 152 | // Without this, we can't play the video after pausing it |
154 | // https://github.com/videojs/video.js/blob/master/src/js/player.js#L1633 | 153 | // https://github.com/videojs/video.js/blob/master/src/js/player.js#L1633 |
155 | this.player.src = () => true | 154 | (this.player as any).src = () => true |
156 | const oldPlaybackRate = this.player.playbackRate() | 155 | const oldPlaybackRate = this.player.playbackRate() |
157 | 156 | ||
158 | const previousVideoFile = this.currentVideoFile | 157 | const previousVideoFile = this.currentVideoFile |
@@ -333,7 +332,7 @@ class WebTorrentPlugin extends Plugin { | |||
333 | 332 | ||
334 | const playPromise = this.player.play() | 333 | const playPromise = this.player.play() |
335 | if (playPromise !== undefined) { | 334 | if (playPromise !== undefined) { |
336 | return playPromise.then(done) | 335 | return playPromise.then(() => done()) |
337 | .catch((err: Error) => { | 336 | .catch((err: Error) => { |
338 | if (err.message.indexOf('The play() request was interrupted by a call to pause()') !== -1) { | 337 | if (err.message.indexOf('The play() request was interrupted by a call to pause()') !== -1) { |
339 | return | 338 | return |
@@ -426,8 +425,8 @@ class WebTorrentPlugin extends Plugin { | |||
426 | } | 425 | } |
427 | 426 | ||
428 | // Proxy first play | 427 | // Proxy first play |
429 | const oldPlay = this.player.play.bind(this.player) | 428 | const oldPlay = this.player.play.bind(this.player); |
430 | this.player.play = () => { | 429 | (this.player as any).play = () => { |
431 | this.player.addClass('vjs-has-big-play-button-clicked') | 430 | this.player.addClass('vjs-has-big-play-button-clicked') |
432 | this.player.play = oldPlay | 431 | this.player.play = oldPlay |
433 | 432 | ||
@@ -619,7 +618,7 @@ class WebTorrentPlugin extends Plugin { | |||
619 | video: qualityLevelsPayload | 618 | video: qualityLevelsPayload |
620 | } | 619 | } |
621 | } | 620 | } |
622 | this.player.tech_.trigger('loadedqualitydata', payload) | 621 | this.player.tech(true).trigger('loadedqualitydata', payload) |
623 | } | 622 | } |
624 | 623 | ||
625 | private buildQualityLabel (file: VideoFile) { | 624 | private buildQualityLabel (file: VideoFile) { |
@@ -651,9 +650,9 @@ class WebTorrentPlugin extends Plugin { | |||
651 | return | 650 | return |
652 | } | 651 | } |
653 | 652 | ||
654 | for (let i = 0; i < qualityLevels; i++) { | 653 | for (let i = 0; i < qualityLevels.length; i++) { |
655 | const q = this.player.qualityLevels[i] | 654 | const q = qualityLevels[i] |
656 | if (q.height === resolutionId) qualityLevels.selectedIndex = i | 655 | if (q.height === resolutionId) qualityLevels.selectedIndex_ = i |
657 | } | 656 | } |
658 | } | 657 | } |
659 | } | 658 | } |
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss index 5dacdd73b..fa2452231 100644 --- a/client/src/sass/application.scss +++ b/client/src/sass/application.scss | |||
@@ -32,7 +32,7 @@ body { | |||
32 | --menuForegroundColor: #{$menu-color}; | 32 | --menuForegroundColor: #{$menu-color}; |
33 | --submenuColor: #{$sub-menu-color}; | 33 | --submenuColor: #{$sub-menu-color}; |
34 | 34 | ||
35 | --inputColor: #{$input-background-color}; | 35 | --inputBackgroundColor: #{$input-background-color}; |
36 | --inputPlaceholderColor: #{$input-placeholder-color}; | 36 | --inputPlaceholderColor: #{$input-placeholder-color}; |
37 | 37 | ||
38 | --actionButtonColor: #{$grey-foreground-color}; | 38 | --actionButtonColor: #{$grey-foreground-color}; |
@@ -61,7 +61,7 @@ strong { | |||
61 | 61 | ||
62 | input.readonly { | 62 | input.readonly { |
63 | /* Force blank on readonly inputs */ | 63 | /* Force blank on readonly inputs */ |
64 | background-color: var(--inputColor) !important; | 64 | background-color: var(--inputBackgroundColor) !important; |
65 | } | 65 | } |
66 | 66 | ||
67 | input, textarea { | 67 | input, textarea { |
@@ -202,26 +202,6 @@ label { | |||
202 | to { transform: scale(1) rotate(360deg);} | 202 | to { transform: scale(1) rotate(360deg);} |
203 | } | 203 | } |
204 | 204 | ||
205 | .orange-button { | ||
206 | @include peertube-button; | ||
207 | @include orange-button; | ||
208 | } | ||
209 | |||
210 | .orange-button-link { | ||
211 | @include peertube-button-link; | ||
212 | @include orange-button; | ||
213 | } | ||
214 | |||
215 | .grey-button { | ||
216 | @include peertube-button; | ||
217 | @include grey-button; | ||
218 | } | ||
219 | |||
220 | .grey-button-link { | ||
221 | @include peertube-button-link; | ||
222 | @include grey-button; | ||
223 | } | ||
224 | |||
225 | // In tables, don't have a hover different background | 205 | // In tables, don't have a hover different background |
226 | table { | 206 | table { |
227 | .action-button-edit, .action-button-delete { | 207 | .action-button-edit, .action-button-delete { |
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss index 136eddd3a..317781e0e 100644 --- a/client/src/sass/include/_mixins.scss +++ b/client/src/sass/include/_mixins.scss | |||
@@ -77,11 +77,17 @@ | |||
77 | } | 77 | } |
78 | } | 78 | } |
79 | 79 | ||
80 | @mixin button-focus-visible-shadow($color) { | ||
81 | &.focus-visible { | ||
82 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 4px $color; | ||
83 | } | ||
84 | } | ||
85 | |||
80 | @mixin peertube-input-text($width) { | 86 | @mixin peertube-input-text($width) { |
81 | display: inline-block; | 87 | display: inline-block; |
82 | height: $button-height; | 88 | height: $button-height; |
83 | width: $width; | 89 | width: $width; |
84 | background: var(--inputColor); | 90 | background: var(--inputBackgroundColor); |
85 | border: 1px solid #C6C6C6; | 91 | border: 1px solid #C6C6C6; |
86 | border-radius: 3px; | 92 | border-radius: 3px; |
87 | padding-left: 15px; | 93 | padding-left: 15px; |
@@ -118,6 +124,8 @@ | |||
118 | } | 124 | } |
119 | 125 | ||
120 | @mixin orange-button { | 126 | @mixin orange-button { |
127 | @include button-focus-visible-shadow(var(--mainHoverColor)); | ||
128 | |||
121 | &, &:active, &:focus { | 129 | &, &:active, &:focus { |
122 | color: #fff; | 130 | color: #fff; |
123 | background-color: var(--mainColor); | 131 | background-color: var(--mainColor); |
@@ -169,7 +177,6 @@ | |||
169 | text-align: center; | 177 | text-align: center; |
170 | padding: 0 17px 0 13px; | 178 | padding: 0 17px 0 13px; |
171 | cursor: pointer; | 179 | cursor: pointer; |
172 | outline: 0; | ||
173 | } | 180 | } |
174 | 181 | ||
175 | @mixin peertube-button-link { | 182 | @mixin peertube-button-link { |
@@ -254,7 +261,7 @@ | |||
254 | width: $width; | 261 | width: $width; |
255 | border-radius: 3px; | 262 | border-radius: 3px; |
256 | overflow: hidden; | 263 | overflow: hidden; |
257 | background: var(--inputColor); | 264 | background: var(--inputBackgroundColor); |
258 | position: relative; | 265 | position: relative; |
259 | font-size: 15px; | 266 | font-size: 15px; |
260 | 267 | ||
diff --git a/client/src/sass/include/_variables.scss b/client/src/sass/include/_variables.scss index 5b5ac9adc..e087a2548 100644 --- a/client/src/sass/include/_variables.scss +++ b/client/src/sass/include/_variables.scss | |||
@@ -81,7 +81,7 @@ $variables: ( | |||
81 | --menuForegroundColor: var(--menuForegroundColor), | 81 | --menuForegroundColor: var(--menuForegroundColor), |
82 | --submenuColor: var(--submenuColor), | 82 | --submenuColor: var(--submenuColor), |
83 | 83 | ||
84 | --inputColor: var(--inputColor), | 84 | --inputBackgroundColor: var(--inputBackgroundColor), |
85 | --inputPlaceholderColor: var(--inputPlaceholderColor), | 85 | --inputPlaceholderColor: var(--inputPlaceholderColor), |
86 | 86 | ||
87 | --actionButtonColor: var(--actionButtonColor), | 87 | --actionButtonColor: var(--actionButtonColor), |
diff --git a/client/src/sass/player/_player-variables.scss b/client/src/sass/player/_player-variables.scss index 0c2359ac7..935a60b49 100644 --- a/client/src/sass/player/_player-variables.scss +++ b/client/src/sass/player/_player-variables.scss | |||
@@ -1,7 +1,7 @@ | |||
1 | $primary-foreground-color: #fff; | 1 | $primary-foreground-color: #fff; |
2 | $primary-foreground-opacity: 0.9; | 2 | $primary-foreground-opacity: 0.9; |
3 | $primary-foreground-opacity-hover: 1; | 3 | $primary-foreground-opacity-hover: 1; |
4 | $primary-background-color: #000; | 4 | $primary-background-color: rgba(0, 0, 0, 0.8); |
5 | 5 | ||
6 | $font-size: 13px; | 6 | $font-size: 13px; |
7 | $control-bar-height: 34px; | 7 | $control-bar-height: 34px; |
diff --git a/client/src/sass/player/bezels.scss b/client/src/sass/player/bezels.scss index ff3448511..853a030a3 100644 --- a/client/src/sass/player/bezels.scss +++ b/client/src/sass/player/bezels.scss | |||
@@ -32,11 +32,3 @@ | |||
32 | fill: #fff; | 32 | fill: #fff; |
33 | } | 33 | } |
34 | } | 34 | } |
35 | |||
36 | .video-js { | ||
37 | |||
38 | .vjs-bezel-content { | ||
39 | |||
40 | } | ||
41 | |||
42 | } | ||
diff --git a/client/src/sass/player/peertube-skin.scss b/client/src/sass/player/peertube-skin.scss index 41e2a535c..f80106428 100644 --- a/client/src/sass/player/peertube-skin.scss +++ b/client/src/sass/player/peertube-skin.scss | |||
@@ -21,6 +21,12 @@ body { | |||
21 | 21 | ||
22 | .vjs-dock-text { | 22 | .vjs-dock-text { |
23 | padding-right: 10px; | 23 | padding-right: 10px; |
24 | background: linear-gradient(to bottom, rgba(0, 0, 0, .6) 0, rgba(0, 0, 0, 0.2) 70%, rgba(0, 0, 0, 0) 100%); | ||
25 | } | ||
26 | |||
27 | .vjs-dock-title, | ||
28 | .vjs-dock-description { | ||
29 | text-shadow: 0 0 2px rgba(0, 0, 0, .5); | ||
24 | } | 30 | } |
25 | 31 | ||
26 | .vjs-dock-description { | 32 | .vjs-dock-description { |
@@ -55,7 +61,7 @@ body { | |||
55 | $big-play-width: 1.2em; | 61 | $big-play-width: 1.2em; |
56 | $big-play-height: 1.2em; | 62 | $big-play-height: 1.2em; |
57 | 63 | ||
58 | border: 4px solid #fff; | 64 | border: 2px solid #fff; |
59 | border-radius: 100%; | 65 | border-radius: 100%; |
60 | 66 | ||
61 | left: 50%; | 67 | left: 50%; |
@@ -185,7 +191,6 @@ body { | |||
185 | 191 | ||
186 | .vjs-play-progress { | 192 | .vjs-play-progress { |
187 | background: var(--embedForegroundColor); | 193 | background: var(--embedForegroundColor); |
188 | transition: all .2s ease 0s; | ||
189 | 194 | ||
190 | // Not display the circle if the progress is not hovered | 195 | // Not display the circle if the progress is not hovered |
191 | &::before { | 196 | &::before { |
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index c91ae08b9..d5b42a025 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts | |||
@@ -1,15 +1,11 @@ | |||
1 | import './embed.scss' | 1 | import './embed.scss' |
2 | 2 | ||
3 | import { | 3 | import { |
4 | getCompleteLocale, | ||
5 | is18nLocale, | ||
6 | isDefaultLocale, | ||
7 | peertubeTranslate, | 4 | peertubeTranslate, |
8 | ResultList, | 5 | ResultList, |
9 | ServerConfig, | 6 | ServerConfig, |
10 | VideoDetails | 7 | VideoDetails |
11 | } from '../../../../shared' | 8 | } from '../../../../shared' |
12 | import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings' | ||
13 | import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model' | 9 | import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model' |
14 | import { | 10 | import { |
15 | P2PMediaLoaderOptions, | 11 | P2PMediaLoaderOptions, |
@@ -19,10 +15,14 @@ import { | |||
19 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' | 15 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' |
20 | import { PeerTubeEmbedApi } from './embed-api' | 16 | import { PeerTubeEmbedApi } from './embed-api' |
21 | import { TranslationsManager } from '../../assets/player/translations-manager' | 17 | import { TranslationsManager } from '../../assets/player/translations-manager' |
18 | import { VideoJsPlayer } from 'video.js' | ||
19 | import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings' | ||
20 | |||
21 | type Translations = { [ id: string ]: string } | ||
22 | 22 | ||
23 | export class PeerTubeEmbed { | 23 | export class PeerTubeEmbed { |
24 | videoElement: HTMLVideoElement | 24 | videoElement: HTMLVideoElement |
25 | player: any | 25 | player: VideoJsPlayer |
26 | api: PeerTubeEmbedApi = null | 26 | api: PeerTubeEmbedApi = null |
27 | autoplay: boolean | 27 | autoplay: boolean |
28 | controls: boolean | 28 | controls: boolean |
@@ -71,7 +71,7 @@ export class PeerTubeEmbed { | |||
71 | element.parentElement.removeChild(element) | 71 | element.parentElement.removeChild(element) |
72 | } | 72 | } |
73 | 73 | ||
74 | displayError (text: string, translations?: { [ id: string ]: string }) { | 74 | displayError (text: string, translations?: Translations) { |
75 | // Remove video element | 75 | // Remove video element |
76 | if (this.videoElement) this.removeElement(this.videoElement) | 76 | if (this.videoElement) this.removeElement(this.videoElement) |
77 | 77 | ||
@@ -90,12 +90,12 @@ export class PeerTubeEmbed { | |||
90 | errorText.innerHTML = translatedText | 90 | errorText.innerHTML = translatedText |
91 | } | 91 | } |
92 | 92 | ||
93 | videoNotFound (translations?: { [ id: string ]: string }) { | 93 | videoNotFound (translations?: Translations) { |
94 | const text = 'This video does not exist.' | 94 | const text = 'This video does not exist.' |
95 | this.displayError(text, translations) | 95 | this.displayError(text, translations) |
96 | } | 96 | } |
97 | 97 | ||
98 | videoFetchError (translations?: { [ id: string ]: string }) { | 98 | videoFetchError (translations?: Translations) { |
99 | const text = 'We cannot fetch the video. Please try again later.' | 99 | const text = 'We cannot fetch the video. Please try again later.' |
100 | this.displayError(text, translations) | 100 | this.displayError(text, translations) |
101 | } | 101 | } |
@@ -237,7 +237,7 @@ export class PeerTubeEmbed { | |||
237 | }) | 237 | }) |
238 | } | 238 | } |
239 | 239 | ||
240 | this.player = await PeertubePlayerManager.initialize(this.mode, options, (player: any) => this.player = player) | 240 | this.player = await PeertubePlayerManager.initialize(this.mode, options, (player: VideoJsPlayer) => this.player = player) |
241 | this.player.on('customError', (event: any, data: any) => this.handleError(data.err, serverTranslations)) | 241 | this.player.on('customError', (event: any, data: any) => this.handleError(data.err, serverTranslations)) |
242 | 242 | ||
243 | window[ 'videojsPlayer' ] = this.player | 243 | window[ 'videojsPlayer' ] = this.player |
@@ -261,19 +261,19 @@ export class PeerTubeEmbed { | |||
261 | } | 261 | } |
262 | 262 | ||
263 | private async buildDock (videoInfo: VideoDetails, configResponse: Response) { | 263 | private async buildDock (videoInfo: VideoDetails, configResponse: Response) { |
264 | if (this.controls) { | 264 | if (!this.controls) return |
265 | const title = this.title ? videoInfo.name : undefined | ||
266 | 265 | ||
267 | const config: ServerConfig = await configResponse.json() | 266 | const title = this.title ? videoInfo.name : undefined |
268 | const description = config.tracker.enabled && this.warningTitle | ||
269 | ? '<span class="text">' + this.player.localize('Watching this video may reveal your IP address to others.') + '</span>' | ||
270 | : undefined | ||
271 | 267 | ||
272 | this.player.dock({ | 268 | const config: ServerConfig = await configResponse.json() |
273 | title, | 269 | const description = config.tracker.enabled && this.warningTitle |
274 | description | 270 | ? '<span class="text">' + peertubeTranslate('Watching this video may reveal your IP address to others.') + '</span>' |
275 | }) | 271 | : undefined |
276 | } | 272 | |
273 | this.player.dock({ | ||
274 | title, | ||
275 | description | ||
276 | }) | ||
277 | } | 277 | } |
278 | 278 | ||
279 | private buildCSS () { | 279 | private buildCSS () { |
diff --git a/client/tsconfig.json b/client/tsconfig.json index 8824c4f7c..c4f2d6a6a 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json | |||
@@ -26,7 +26,7 @@ | |||
26 | "paths": { | 26 | "paths": { |
27 | "@app/*": [ "src/app/*" ], | 27 | "@app/*": [ "src/app/*" ], |
28 | "@shared/*": [ "../shared/*" ], | 28 | "@shared/*": [ "../shared/*" ], |
29 | "video.js": [ "node_modules/video.js/dist/alt/video.core.js" ], | 29 | "video.js": [ "node_modules/video.js/dist/alt/video.core.novtt" ], |
30 | "fs": [ "src/shims/noop" ], | 30 | "fs": [ "src/shims/noop" ], |
31 | "http": [ "src/shims/http" ], | 31 | "http": [ "src/shims/http" ], |
32 | "https": [ "src/shims/https" ], | 32 | "https": [ "src/shims/https" ], |
diff --git a/client/webpack/webpack.video-embed.js b/client/webpack/webpack.video-embed.js index 909048cca..f6d532556 100644 --- a/client/webpack/webpack.video-embed.js +++ b/client/webpack/webpack.video-embed.js | |||
@@ -27,7 +27,7 @@ module.exports = function () { | |||
27 | modules: [ helpers.root('src'), helpers.root('node_modules') ], | 27 | modules: [ helpers.root('src'), helpers.root('node_modules') ], |
28 | 28 | ||
29 | alias: { | 29 | alias: { |
30 | 'video.js$': path.resolve('node_modules/video.js/dist/alt/video.core.js') | 30 | 'video.js$': path.resolve('node_modules/video.js/dist/alt/video.core.novtt.js') |
31 | } | 31 | } |
32 | }, | 32 | }, |
33 | 33 | ||
diff --git a/client/yarn.lock b/client/yarn.lock index 0855a2570..1b9c2cef1 100644 --- a/client/yarn.lock +++ b/client/yarn.lock | |||
@@ -987,11 +987,6 @@ | |||
987 | semver "6.3.0" | 987 | semver "6.3.0" |
988 | semver-intersect "1.4.0" | 988 | semver-intersect "1.4.0" |
989 | 989 | ||
990 | "@streamroot/videojs-hlsjs-plugin@^1.0.10": | ||
991 | version "1.0.13" | ||
992 | resolved "https://registry.yarnpkg.com/@streamroot/videojs-hlsjs-plugin/-/videojs-hlsjs-plugin-1.0.13.tgz#ae3afb3a5a3cd90e7b424b6b4cb14de1cde40836" | ||
993 | integrity sha512-A55213sFj8nuoj23YiR0r73cRV4dlnSwXGwT1Qiu+oqhsauhqN+lHSRHFztMIU4EMf2Cafvv5P4R+A2c/Uj6nw== | ||
994 | |||
995 | "@types/bittorrent-protocol@*": | 990 | "@types/bittorrent-protocol@*": |
996 | version "2.2.4" | 991 | version "2.2.4" |
997 | resolved "https://registry.yarnpkg.com/@types/bittorrent-protocol/-/bittorrent-protocol-2.2.4.tgz#7dc0716924bc6a904753d39846ad235c7dab4641" | 992 | resolved "https://registry.yarnpkg.com/@types/bittorrent-protocol/-/bittorrent-protocol-2.2.4.tgz#7dc0716924bc6a904753d39846ad235c7dab4641" |
@@ -1045,6 +1040,11 @@ | |||
1045 | resolved "https://registry.yarnpkg.com/@types/jschannel/-/jschannel-1.0.1.tgz#79d582ccf42554c8457230526a3054d018d559f0" | 1040 | resolved "https://registry.yarnpkg.com/@types/jschannel/-/jschannel-1.0.1.tgz#79d582ccf42554c8457230526a3054d018d559f0" |
1046 | integrity sha512-S34NuOoOOKXbft3f9GDeLKp777ABCGArZaqUWOuu1Xn+1S75Osmk8kCeqmw5x2TuASyjE082DwDAuoaXNIRCTw== | 1041 | integrity sha512-S34NuOoOOKXbft3f9GDeLKp777ABCGArZaqUWOuu1Xn+1S75Osmk8kCeqmw5x2TuASyjE082DwDAuoaXNIRCTw== |
1047 | 1042 | ||
1043 | "@types/linkify-it@*": | ||
1044 | version "2.1.0" | ||
1045 | resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-2.1.0.tgz#ea3dd64c4805597311790b61e872cbd1ed2cd806" | ||
1046 | integrity sha512-Q7DYAOi9O/+cLLhdaSvKdaumWyHbm7HAk/bFwwyTuU0arR5yyCeW5GOoqt4tJTpDRxhpx9Q8kQL6vMpuw9hDSw== | ||
1047 | |||
1048 | "@types/linkifyjs@^2.1.2": | 1048 | "@types/linkifyjs@^2.1.2": |
1049 | version "2.1.2" | 1049 | version "2.1.2" |
1050 | resolved "https://registry.yarnpkg.com/@types/linkifyjs/-/linkifyjs-2.1.2.tgz#8244f4e6d7be65359cc25a34da8977fce87a7b2e" | 1050 | resolved "https://registry.yarnpkg.com/@types/linkifyjs/-/linkifyjs-2.1.2.tgz#8244f4e6d7be65359cc25a34da8977fce87a7b2e" |
@@ -1071,10 +1071,12 @@ | |||
1071 | dependencies: | 1071 | dependencies: |
1072 | "@types/node" "*" | 1072 | "@types/node" "*" |
1073 | 1073 | ||
1074 | "@types/markdown-it@^0.0.5": | 1074 | "@types/markdown-it@^0.0.9": |
1075 | version "0.0.5" | 1075 | version "0.0.9" |
1076 | resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.5.tgz#5cdcbe08e81075d5dbf15466b311359b02a30c2b" | 1076 | resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.9.tgz#a5d552f95216c478e0a27a5acc1b28dcffd989ce" |
1077 | integrity sha512-Bhc4jTJ3g+WU+dBvyhwwssHifjqapauyjV+0cTWVWRjwDAaK9PebZBFpLJmoOCp47qlkDeeT1Y9sV9LyyaG02w== | 1077 | integrity sha512-IFSepyZXbF4dgSvsk8EsgaQ/8Msv1I5eTL0BZ0X3iGO9jw6tCVtPG8HchIPm3wrkmGdqZOD42kE0zplVi1gYDA== |
1078 | dependencies: | ||
1079 | "@types/linkify-it" "*" | ||
1078 | 1080 | ||
1079 | "@types/minimatch@*": | 1081 | "@types/minimatch@*": |
1080 | version "3.0.3" | 1082 | version "3.0.3" |
@@ -1157,10 +1159,10 @@ | |||
1157 | resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" | 1159 | resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" |
1158 | integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== | 1160 | integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== |
1159 | 1161 | ||
1160 | "@types/video.js@^7.2.5": | 1162 | "@types/video.js@^7.3.3": |
1161 | version "7.2.15" | 1163 | version "7.3.3" |
1162 | resolved "https://registry.yarnpkg.com/@types/video.js/-/video.js-7.2.15.tgz#03d950f01c985a5082ead4d1b73064455a1c8c6f" | 1164 | resolved "https://registry.yarnpkg.com/@types/video.js/-/video.js-7.3.3.tgz#b6870d954473dfd694e10b55a90c0f3be8522da3" |
1163 | integrity sha512-NsojVfvTwdVqDe0+vJaoHOO2iuLm0sp/u8jEsZeLGsM3gNfg5WIOFd6NC0cQR9JHUuDPPSPF70jxdklGWm5jhQ== | 1165 | integrity sha512-yAb46+4A0dKFxOQRVLoLyfC/S/BmHLE10MxPXt/t88+7R4GWLHosHelVtYpKBRykjptdkqfQXNRXoQzDeKm6MA== |
1164 | 1166 | ||
1165 | "@types/webpack-sources@^0.1.5": | 1167 | "@types/webpack-sources@^0.1.5": |
1166 | version "0.1.5" | 1168 | version "0.1.5" |
@@ -2586,6 +2588,29 @@ chardet@^0.7.0: | |||
2586 | resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" | 2588 | resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" |
2587 | integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== | 2589 | integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== |
2588 | 2590 | ||
2591 | chart.js@^2.9.3: | ||
2592 | version "2.9.3" | ||
2593 | resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.9.3.tgz#ae3884114dafd381bc600f5b35a189138aac1ef7" | ||
2594 | integrity sha512-+2jlOobSk52c1VU6fzkh3UwqHMdSlgH1xFv9FKMqHiNCpXsGPQa/+81AFa+i3jZ253Mq9aAycPwDjnn1XbRNNw== | ||
2595 | dependencies: | ||
2596 | chartjs-color "^2.1.0" | ||
2597 | moment "^2.10.2" | ||
2598 | |||
2599 | chartjs-color-string@^0.6.0: | ||
2600 | version "0.6.0" | ||
2601 | resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz#1df096621c0e70720a64f4135ea171d051402f71" | ||
2602 | integrity sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A== | ||
2603 | dependencies: | ||
2604 | color-name "^1.0.0" | ||
2605 | |||
2606 | chartjs-color@^2.1.0: | ||
2607 | version "2.4.1" | ||
2608 | resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.4.1.tgz#6118bba202fe1ea79dd7f7c0f9da93467296c3b0" | ||
2609 | integrity sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w== | ||
2610 | dependencies: | ||
2611 | chartjs-color-string "^0.6.0" | ||
2612 | color-convert "^1.9.3" | ||
2613 | |||
2589 | check-types@^8.0.3: | 2614 | check-types@^8.0.3: |
2590 | version "8.0.3" | 2615 | version "8.0.3" |
2591 | resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552" | 2616 | resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552" |
@@ -2800,7 +2825,7 @@ collection-visit@^1.0.0: | |||
2800 | map-visit "^1.0.0" | 2825 | map-visit "^1.0.0" |
2801 | object-visit "^1.0.0" | 2826 | object-visit "^1.0.0" |
2802 | 2827 | ||
2803 | color-convert@^1.9.0: | 2828 | color-convert@^1.9.0, color-convert@^1.9.3: |
2804 | version "1.9.3" | 2829 | version "1.9.3" |
2805 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" | 2830 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" |
2806 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== | 2831 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== |
@@ -2812,6 +2837,11 @@ color-name@1.1.3: | |||
2812 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" | 2837 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" |
2813 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= | 2838 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= |
2814 | 2839 | ||
2840 | color-name@^1.0.0: | ||
2841 | version "1.1.4" | ||
2842 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" | ||
2843 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== | ||
2844 | |||
2815 | colors@1.1.2: | 2845 | colors@1.1.2: |
2816 | version "1.1.2" | 2846 | version "1.1.2" |
2817 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" | 2847 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" |
@@ -6941,6 +6971,11 @@ mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: | |||
6941 | dependencies: | 6971 | dependencies: |
6942 | minimist "0.0.8" | 6972 | minimist "0.0.8" |
6943 | 6973 | ||
6974 | moment@^2.10.2: | ||
6975 | version "2.24.0" | ||
6976 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" | ||
6977 | integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== | ||
6978 | |||
6944 | mousetrap@^1.6.0: | 6979 | mousetrap@^1.6.0: |
6945 | version "1.6.3" | 6980 | version "1.6.3" |
6946 | resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.3.tgz#80fee49665fd478bccf072c9d46bdf1bfed3558a" | 6981 | resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.3.tgz#80fee49665fd478bccf072c9d46bdf1bfed3558a" |
@@ -10809,6 +10844,11 @@ void-elements@^2.0.0: | |||
10809 | resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" | 10844 | resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" |
10810 | integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= | 10845 | integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= |
10811 | 10846 | ||
10847 | vtt.js@^0.13.0: | ||
10848 | version "0.13.0" | ||
10849 | resolved "https://registry.yarnpkg.com/vtt.js/-/vtt.js-0.13.0.tgz#955c667b34d5325b2012cb9e8ba9bad6e0b11ff8" | ||
10850 | integrity sha1-lVxmezTVMlsgEsuei6m61uCxH/g= | ||
10851 | |||
10812 | watchpack@^1.6.0: | 10852 | watchpack@^1.6.0: |
10813 | version "1.6.0" | 10853 | version "1.6.0" |
10814 | resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" | 10854 | resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" |
diff --git a/config/test.yaml b/config/test.yaml index 5758c1887..74979f3a7 100644 --- a/config/test.yaml +++ b/config/test.yaml | |||
@@ -40,18 +40,18 @@ contact_form: | |||
40 | 40 | ||
41 | redundancy: | 41 | redundancy: |
42 | videos: | 42 | videos: |
43 | check_interval: '10 minutes' | 43 | check_interval: '1 minute' |
44 | strategies: | 44 | strategies: |
45 | - | 45 | - |
46 | size: '10MB' | 46 | size: '1000MB' |
47 | min_lifetime: '10 minutes' | 47 | min_lifetime: '10 minutes' |
48 | strategy: 'most-views' | 48 | strategy: 'most-views' |
49 | - | 49 | - |
50 | size: '10MB' | 50 | size: '1000MB' |
51 | min_lifetime: '10 minutes' | 51 | min_lifetime: '10 minutes' |
52 | strategy: 'trending' | 52 | strategy: 'trending' |
53 | - | 53 | - |
54 | size: '10MB' | 54 | size: '1000MB' |
55 | min_lifetime: '10 minutes' | 55 | min_lifetime: '10 minutes' |
56 | strategy: 'recently-added' | 56 | strategy: 'recently-added' |
57 | min_views: 1 | 57 | min_views: 1 |
diff --git a/package.json b/package.json index d4858725a..0a5484d2a 100644 --- a/package.json +++ b/package.json | |||
@@ -5,7 +5,7 @@ | |||
5 | "private": true, | 5 | "private": true, |
6 | "licence": "AGPL-3.0", | 6 | "licence": "AGPL-3.0", |
7 | "engines": { | 7 | "engines": { |
8 | "node": ">=8.x" | 8 | "node": ">=10.x" |
9 | }, | 9 | }, |
10 | "bin": { | 10 | "bin": { |
11 | "peertube": "dist/server/tools/peertube.js" | 11 | "peertube": "dist/server/tools/peertube.js" |
@@ -37,11 +37,10 @@ | |||
37 | "i18n:generate": "scripty", | 37 | "i18n:generate": "scripty", |
38 | "plugin:install": "node ./dist/scripts/plugin/install.js", | 38 | "plugin:install": "node ./dist/scripts/plugin/install.js", |
39 | "plugin:uninstall": "node ./dist/scripts/plugin/uninstall.js", | 39 | "plugin:uninstall": "node ./dist/scripts/plugin/uninstall.js", |
40 | "i18n:xliff2json": "node ./dist/scripts/i18n/xliff2json.js", | ||
41 | "i18n:create-custom-files": "node ./dist/scripts/i18n/create-custom-files.js", | 40 | "i18n:create-custom-files": "node ./dist/scripts/i18n/create-custom-files.js", |
42 | "reset-password": "node ./dist/scripts/reset-password.js", | 41 | "reset-password": "node ./dist/scripts/reset-password.js", |
43 | "play": "scripty", | 42 | "play": "scripty", |
44 | "dev": "scripty", | 43 | "dev": "sh ./scripts/dev/index.sh", |
45 | "dev:server": "sh ./scripts/dev/server.sh", | 44 | "dev:server": "sh ./scripts/dev/server.sh", |
46 | "dev:embed": "scripty", | 45 | "dev:embed": "scripty", |
47 | "dev:client": "sh ./scripts/dev/client.sh", | 46 | "dev:client": "sh ./scripts/dev/client.sh", |
@@ -64,7 +63,7 @@ | |||
64 | "ng": "ng", | 63 | "ng": "ng", |
65 | "nodemon": "nodemon", | 64 | "nodemon": "nodemon", |
66 | "ts-node": "ts-node", | 65 | "ts-node": "ts-node", |
67 | "tslint": "tslint", | 66 | "eslint": "eslint", |
68 | "concurrently": "concurrently", | 67 | "concurrently": "concurrently", |
69 | "mocha-parallel-tests": "mocha-parallel-tests", | 68 | "mocha-parallel-tests": "mocha-parallel-tests", |
70 | "sasslint": "sass-lint --verbose --no-exit", | 69 | "sasslint": "sass-lint --verbose --no-exit", |
@@ -78,9 +77,6 @@ | |||
78 | "swagger-cli": "swagger-cli", | 77 | "swagger-cli": "swagger-cli", |
79 | "sass-lint": "sass-lint" | 78 | "sass-lint": "sass-lint" |
80 | }, | 79 | }, |
81 | "resolutions": { | ||
82 | "@types/bluebird": "3.5.27" | ||
83 | }, | ||
84 | "dependencies": { | 80 | "dependencies": { |
85 | "apicache": "^1.4.0", | 81 | "apicache": "^1.4.0", |
86 | "async": "^3.0.1", | 82 | "async": "^3.0.1", |
@@ -100,7 +96,7 @@ | |||
100 | "express": "^4.12.4", | 96 | "express": "^4.12.4", |
101 | "express-oauth-server": "^2.0.0", | 97 | "express-oauth-server": "^2.0.0", |
102 | "express-rate-limit": "^4.0.4", | 98 | "express-rate-limit": "^4.0.4", |
103 | "express-validator": "^6.1.1", | 99 | "express-validator": "^6.4.0", |
104 | "flat": "^5.0.0", | 100 | "flat": "^5.0.0", |
105 | "fluent-ffmpeg": "^2.1.0", | 101 | "fluent-ffmpeg": "^2.1.0", |
106 | "fs-extra": "^8.0.1", | 102 | "fs-extra": "^8.0.1", |
@@ -109,7 +105,7 @@ | |||
109 | "ip-anonymize": "^0.1.0", | 105 | "ip-anonymize": "^0.1.0", |
110 | "ipaddr.js": "1.9.1", | 106 | "ipaddr.js": "1.9.1", |
111 | "is-cidr": "^3.0.0", | 107 | "is-cidr": "^3.0.0", |
112 | "iso-639-3": "^1.0.1", | 108 | "iso-639-3": "^2.0.0", |
113 | "js-yaml": "^3.5.4", | 109 | "js-yaml": "^3.5.4", |
114 | "jsonld": "~2.0.1", | 110 | "jsonld": "~2.0.1", |
115 | "lodash": "^4.17.10", | 111 | "lodash": "^4.17.10", |
@@ -131,7 +127,7 @@ | |||
131 | "scripty": "^1.5.0", | 127 | "scripty": "^1.5.0", |
132 | "sequelize": "5.21.3", | 128 | "sequelize": "5.21.3", |
133 | "sequelize-typescript": "^1.0.0-beta.4", | 129 | "sequelize-typescript": "^1.0.0-beta.4", |
134 | "sharp": "^0.23.3", | 130 | "sharp": "^0.24.0", |
135 | "sitemap": "^5.0.0", | 131 | "sitemap": "^5.0.0", |
136 | "socket.io": "^2.2.0", | 132 | "socket.io": "^2.2.0", |
137 | "srt-to-vtt": "^1.1.2", | 133 | "srt-to-vtt": "^1.1.2", |
@@ -143,16 +139,16 @@ | |||
143 | "webtorrent": "^0.107.16", | 139 | "webtorrent": "^0.107.16", |
144 | "winston": "3.2.1", | 140 | "winston": "3.2.1", |
145 | "ws": "^7.0.0", | 141 | "ws": "^7.0.0", |
146 | "youtube-dl": "^2.0.0" | 142 | "youtube-dl": "^3.0.2" |
147 | }, | 143 | }, |
148 | "devDependencies": { | 144 | "devDependencies": { |
149 | "@types/apicache": "^1.2.0", | 145 | "@types/apicache": "^1.2.0", |
150 | "@types/async": "^3.0.0", | 146 | "@types/async": "^3.0.0", |
151 | "@types/async-lock": "^1.1.0", | 147 | "@types/async-lock": "^1.1.0", |
152 | "@types/bcrypt": "^3.0.0", | 148 | "@types/bcrypt": "^3.0.0", |
153 | "@types/bluebird": "3.5.21", | 149 | "@types/bluebird": "3.5.29", |
154 | "@types/body-parser": "^1.16.3", | 150 | "@types/body-parser": "^1.16.3", |
155 | "@types/bull": "3.4.0", | 151 | "@types/bull": "3.12.0", |
156 | "@types/bytes": "^3.0.0", | 152 | "@types/bytes": "^3.0.0", |
157 | "@types/chai": "^4.0.4", | 153 | "@types/chai": "^4.0.4", |
158 | "@types/chai-json-schema": "^1.4.3", | 154 | "@types/chai-json-schema": "^1.4.3", |
@@ -169,7 +165,7 @@ | |||
169 | "@types/maildev": "^0.0.1", | 165 | "@types/maildev": "^0.0.1", |
170 | "@types/memoizee": "^0.4.2", | 166 | "@types/memoizee": "^0.4.2", |
171 | "@types/mkdirp": "^0.5.1", | 167 | "@types/mkdirp": "^0.5.1", |
172 | "@types/mocha": "^5.0.0", | 168 | "@types/mocha": "^7.0.1", |
173 | "@types/morgan": "^1.7.32", | 169 | "@types/morgan": "^1.7.32", |
174 | "@types/multer": "^1.3.3", | 170 | "@types/multer": "^1.3.3", |
175 | "@types/node": "^10.0.8", | 171 | "@types/node": "^10.0.8", |
@@ -178,18 +174,24 @@ | |||
178 | "@types/pem": "^1.9.3", | 174 | "@types/pem": "^1.9.3", |
179 | "@types/redis": "^2.8.5", | 175 | "@types/redis": "^2.8.5", |
180 | "@types/request": "^2.0.3", | 176 | "@types/request": "^2.0.3", |
181 | "@types/sharp": "^0.23.0", | 177 | "@types/sharp": "^0.24.0", |
182 | "@types/socket.io": "^2.1.2", | 178 | "@types/socket.io": "^2.1.2", |
183 | "@types/supertest": "^2.0.3", | 179 | "@types/supertest": "^2.0.3", |
184 | "@types/validator": "^12.0.1", | 180 | "@types/validator": "^12.0.1", |
185 | "@types/webtorrent": "^0.107.0", | 181 | "@types/webtorrent": "^0.107.0", |
186 | "@types/ws": "^6.0.0", | 182 | "@types/ws": "^7.2.1", |
183 | "@typescript-eslint/eslint-plugin": "^2.18.0", | ||
187 | "chai": "^4.1.1", | 184 | "chai": "^4.1.1", |
188 | "chai-json-schema": "^1.5.0", | 185 | "chai-json-schema": "^1.5.0", |
189 | "chai-xml": "^0.3.2", | 186 | "chai-xml": "^0.3.2", |
190 | "concurrently": "^5.0.0", | 187 | "concurrently": "^5.0.0", |
188 | "eslint": "^6.8.0", | ||
189 | "eslint-config-standard-with-typescript": "^12.0.1", | ||
190 | "eslint-plugin-import": "^2.20.1", | ||
191 | "eslint-plugin-node": "^11.0.0", | ||
192 | "eslint-plugin-promise": "^4.2.1", | ||
193 | "eslint-plugin-standard": "^4.0.1", | ||
191 | "libxmljs": "0.19.7", | 194 | "libxmljs": "0.19.7", |
192 | "lint-staged": "^9.2.0", | ||
193 | "maildev": "^1.0.0-rc3", | 195 | "maildev": "^1.0.0-rc3", |
194 | "marked": "^0.8.0", | 196 | "marked": "^0.8.0", |
195 | "marked-man": "^0.7.0", | 197 | "marked-man": "^0.7.0", |
@@ -198,12 +200,9 @@ | |||
198 | "nodemon": "^2.0.1", | 200 | "nodemon": "^2.0.1", |
199 | "source-map-support": "^0.5.0", | 201 | "source-map-support": "^0.5.0", |
200 | "supertest": "^4.0.2", | 202 | "supertest": "^4.0.2", |
201 | "swagger-cli": "^2.2.0", | 203 | "swagger-cli": "^3.0.1", |
202 | "ts-node": "8.5.4", | 204 | "ts-node": "8.6.2", |
203 | "tslint": "^5.7.0", | 205 | "typescript": "^3.7.2" |
204 | "tslint-config-standard": "^9.0.0", | ||
205 | "typescript": "^3.7.2", | ||
206 | "xliff": "^4.0.0" | ||
207 | }, | 206 | }, |
208 | "scripty": { | 207 | "scripty": { |
209 | "silent": true | 208 | "silent": true |
diff --git a/scripts/ci.sh b/scripts/ci.sh index d111b7447..aea009d9f 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh | |||
@@ -12,7 +12,7 @@ killall -q peertube || true | |||
12 | perl -0777 -i -pe 's#proxy:(\n\s+)enabled: false\n\s+url: ""#proxy:$1enabled: true$1url: "http://188.165.225.149:7899"#' config/test.yaml | 12 | perl -0777 -i -pe 's#proxy:(\n\s+)enabled: false\n\s+url: ""#proxy:$1enabled: true$1url: "http://188.165.225.149:7899"#' config/test.yaml |
13 | 13 | ||
14 | if [ "$1" = "misc" ]; then | 14 | if [ "$1" = "misc" ]; then |
15 | npm run build -- --light-fr | 15 | npm run build -- --light |
16 | mocha --timeout 5000 --exit --require ts-node/register --require tsconfig-paths/register --bail server/tests/client.ts \ | 16 | mocha --timeout 5000 --exit --require ts-node/register --require tsconfig-paths/register --bail server/tests/client.ts \ |
17 | server/tests/feeds/index.ts \ | 17 | server/tests/feeds/index.ts \ |
18 | server/tests/misc-endpoints.ts \ | 18 | server/tests/misc-endpoints.ts \ |
@@ -35,7 +35,7 @@ elif [ "$1" = "api-4" ]; then | |||
35 | npm run build:server | 35 | npm run build:server |
36 | sh ./server/tests/api/ci-4.sh 2 | 36 | sh ./server/tests/api/ci-4.sh 2 |
37 | elif [ "$1" = "lint" ]; then | 37 | elif [ "$1" = "lint" ]; then |
38 | npm run tslint -- --project ./tsconfig.json -c ./tslint.json server.ts "server/**/*.ts" "shared/**/*.ts" | 38 | npm run eslint -- --ext .ts "server/**/*.ts" "shared/**/*.ts" |
39 | npm run swagger-cli -- validate support/doc/api/openapi.yaml | 39 | npm run swagger-cli -- validate support/doc/api/openapi.yaml |
40 | 40 | ||
41 | ( cd client | 41 | ( cd client |
diff --git a/scripts/create-import-video-file-job.ts b/scripts/create-import-video-file-job.ts index 204337d55..37738ca40 100644 --- a/scripts/create-import-video-file-job.ts +++ b/scripts/create-import-video-file-job.ts | |||
@@ -38,6 +38,6 @@ async function run () { | |||
38 | } | 38 | } |
39 | 39 | ||
40 | await JobQueue.Instance.init() | 40 | await JobQueue.Instance.init() |
41 | await JobQueue.Instance.createJob({ type: 'video-file-import', payload: dataInput }) | 41 | await JobQueue.Instance.createJobWithPromise({ type: 'video-file-import', payload: dataInput }) |
42 | console.log('Import job for video %s created.', video.uuid) | 42 | console.log('Import job for video %s created.', video.uuid) |
43 | } | 43 | } |
diff --git a/scripts/create-transcoding-job.ts b/scripts/create-transcoding-job.ts index 27170299d..fec58da2e 100755 --- a/scripts/create-transcoding-job.ts +++ b/scripts/create-transcoding-job.ts | |||
@@ -72,7 +72,7 @@ async function run () { | |||
72 | await JobQueue.Instance.init() | 72 | await JobQueue.Instance.init() |
73 | 73 | ||
74 | for (const d of dataInput) { | 74 | for (const d of dataInput) { |
75 | await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: d }) | 75 | await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: d }) |
76 | console.log('Transcoding job for video %s created.', video.uuid) | 76 | console.log('Transcoding job for video %s created.', video.uuid) |
77 | } | 77 | } |
78 | } | 78 | } |
diff --git a/scripts/dev/index.sh b/scripts/dev/index.sh index d221d2fc8..9e89516b8 100755 --- a/scripts/dev/index.sh +++ b/scripts/dev/index.sh | |||
@@ -3,5 +3,5 @@ | |||
3 | set -eu | 3 | set -eu |
4 | 4 | ||
5 | NODE_ENV=test npm run concurrently -- -k \ | 5 | NODE_ENV=test npm run concurrently -- -k \ |
6 | "npm run dev:client -- --skip-server" \ | 6 | "sh scripts/dev/client.sh --skip-server" \ |
7 | "npm run dev:server" | 7 | "sh scripts/dev/server.sh" |
@@ -1,10 +1,6 @@ | |||
1 | import { registerTSPaths } from './server/helpers/register-ts-paths' | 1 | import { registerTSPaths } from './server/helpers/register-ts-paths' |
2 | |||
3 | registerTSPaths() | 2 | registerTSPaths() |
4 | 3 | ||
5 | // FIXME: https://github.com/nodejs/node/pull/16853 | ||
6 | require('tls').DEFAULT_ECDH_CURVE = 'auto' | ||
7 | |||
8 | import { isTestInstance } from './server/helpers/core-utils' | 4 | import { isTestInstance } from './server/helpers/core-utils' |
9 | if (isTestInstance()) { | 5 | if (isTestInstance()) { |
10 | require('source-map-support').install() | 6 | require('source-map-support').install() |
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts index 62412cd62..2812bfe1e 100644 --- a/server/controllers/activitypub/client.ts +++ b/server/controllers/activitypub/client.ts | |||
@@ -14,7 +14,7 @@ import { | |||
14 | videosCustomGetValidator, | 14 | videosCustomGetValidator, |
15 | videosShareValidator | 15 | videosShareValidator |
16 | } from '../../middlewares' | 16 | } from '../../middlewares' |
17 | import { getAccountVideoRateValidator, videoCommentGetValidator } from '../../middlewares/validators' | 17 | import { getAccountVideoRateValidatorFactory, videoCommentGetValidator } from '../../middlewares/validators' |
18 | import { AccountModel } from '../../models/account/account' | 18 | import { AccountModel } from '../../models/account/account' |
19 | import { ActorFollowModel } from '../../models/activitypub/actor-follow' | 19 | import { ActorFollowModel } from '../../models/activitypub/actor-follow' |
20 | import { VideoModel } from '../../models/video/video' | 20 | import { VideoModel } from '../../models/video/video' |
@@ -63,13 +63,13 @@ activityPubClientRouter.get('/accounts?/:name/playlists', | |||
63 | ) | 63 | ) |
64 | activityPubClientRouter.get('/accounts?/:name/likes/:videoId', | 64 | activityPubClientRouter.get('/accounts?/:name/likes/:videoId', |
65 | executeIfActivityPub, | 65 | executeIfActivityPub, |
66 | asyncMiddleware(getAccountVideoRateValidator('like')), | 66 | asyncMiddleware(getAccountVideoRateValidatorFactory('like')), |
67 | getAccountVideoRate('like') | 67 | getAccountVideoRateFactory('like') |
68 | ) | 68 | ) |
69 | activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId', | 69 | activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId', |
70 | executeIfActivityPub, | 70 | executeIfActivityPub, |
71 | asyncMiddleware(getAccountVideoRateValidator('dislike')), | 71 | asyncMiddleware(getAccountVideoRateValidatorFactory('dislike')), |
72 | getAccountVideoRate('dislike') | 72 | getAccountVideoRateFactory('dislike') |
73 | ) | 73 | ) |
74 | 74 | ||
75 | activityPubClientRouter.get('/videos/watch/:id', | 75 | activityPubClientRouter.get('/videos/watch/:id', |
@@ -122,7 +122,7 @@ activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity | |||
122 | activityPubClientRouter.get('/video-channels/:name', | 122 | activityPubClientRouter.get('/video-channels/:name', |
123 | executeIfActivityPub, | 123 | executeIfActivityPub, |
124 | asyncMiddleware(localVideoChannelValidator), | 124 | asyncMiddleware(localVideoChannelValidator), |
125 | asyncMiddleware(videoChannelController) | 125 | videoChannelController |
126 | ) | 126 | ) |
127 | activityPubClientRouter.get('/video-channels/:name/followers', | 127 | activityPubClientRouter.get('/video-channels/:name/followers', |
128 | executeIfActivityPub, | 128 | executeIfActivityPub, |
@@ -154,7 +154,7 @@ activityPubClientRouter.get('/video-playlists/:playlistId', | |||
154 | activityPubClientRouter.get('/video-playlists/:playlistId/:videoId', | 154 | activityPubClientRouter.get('/video-playlists/:playlistId/:videoId', |
155 | executeIfActivityPub, | 155 | executeIfActivityPub, |
156 | asyncMiddleware(videoPlaylistElementAPGetValidator), | 156 | asyncMiddleware(videoPlaylistElementAPGetValidator), |
157 | asyncMiddleware(videoPlaylistElementController) | 157 | videoPlaylistElementController |
158 | ) | 158 | ) |
159 | 159 | ||
160 | // --------------------------------------------------------------------------- | 160 | // --------------------------------------------------------------------------- |
@@ -192,7 +192,7 @@ async function accountPlaylistsController (req: express.Request, res: express.Re | |||
192 | return activityPubResponse(activityPubContextify(activityPubResult), res) | 192 | return activityPubResponse(activityPubContextify(activityPubResult), res) |
193 | } | 193 | } |
194 | 194 | ||
195 | function getAccountVideoRate (rateType: VideoRateType) { | 195 | function getAccountVideoRateFactory (rateType: VideoRateType) { |
196 | return (req: express.Request, res: express.Response) => { | 196 | return (req: express.Request, res: express.Response) => { |
197 | const accountVideoRate = res.locals.accountVideoRate | 197 | const accountVideoRate = res.locals.accountVideoRate |
198 | 198 | ||
@@ -234,7 +234,7 @@ async function videoAnnounceController (req: express.Request, res: express.Respo | |||
234 | 234 | ||
235 | const { activity } = await buildAnnounceWithVideoAudience(share.Actor, share, res.locals.videoAll, undefined) | 235 | const { activity } = await buildAnnounceWithVideoAudience(share.Actor, share, res.locals.videoAll, undefined) |
236 | 236 | ||
237 | return activityPubResponse(activityPubContextify(activity), res) | 237 | return activityPubResponse(activityPubContextify(activity, 'Announce'), res) |
238 | } | 238 | } |
239 | 239 | ||
240 | async function videoAnnouncesController (req: express.Request, res: express.Response) { | 240 | async function videoAnnouncesController (req: express.Request, res: express.Response) { |
@@ -281,7 +281,7 @@ async function videoCommentsController (req: express.Request, res: express.Respo | |||
281 | return activityPubResponse(activityPubContextify(json), res) | 281 | return activityPubResponse(activityPubContextify(json), res) |
282 | } | 282 | } |
283 | 283 | ||
284 | async function videoChannelController (req: express.Request, res: express.Response) { | 284 | function videoChannelController (req: express.Request, res: express.Response) { |
285 | const videoChannel = res.locals.videoChannel | 285 | const videoChannel = res.locals.videoChannel |
286 | 286 | ||
287 | return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res) | 287 | return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res) |
@@ -353,7 +353,7 @@ async function videoPlaylistController (req: express.Request, res: express.Respo | |||
353 | return activityPubResponse(activityPubContextify(object), res) | 353 | return activityPubResponse(activityPubContextify(object), res) |
354 | } | 354 | } |
355 | 355 | ||
356 | async function videoPlaylistElementController (req: express.Request, res: express.Response) { | 356 | function videoPlaylistElementController (req: express.Request, res: express.Response) { |
357 | const videoPlaylistElement = res.locals.videoPlaylistElementAP | 357 | const videoPlaylistElement = res.locals.videoPlaylistElementAP |
358 | 358 | ||
359 | const json = videoPlaylistElement.toActivityPubObject() | 359 | const json = videoPlaylistElement.toActivityPubObject() |
diff --git a/server/controllers/activitypub/inbox.ts b/server/controllers/activitypub/inbox.ts index ca42106b8..3b8fb34a8 100644 --- a/server/controllers/activitypub/inbox.ts +++ b/server/controllers/activitypub/inbox.ts | |||
@@ -46,11 +46,15 @@ const inboxQueue = queue<QueueParam, Error>((task, cb) => { | |||
46 | 46 | ||
47 | processActivities(task.activities, options) | 47 | processActivities(task.activities, options) |
48 | .then(() => cb()) | 48 | .then(() => cb()) |
49 | .catch(err => { | ||
50 | logger.error('Error in process activities.', { err }) | ||
51 | cb() | ||
52 | }) | ||
49 | }) | 53 | }) |
50 | 54 | ||
51 | function inboxController (req: express.Request, res: express.Response) { | 55 | function inboxController (req: express.Request, res: express.Response) { |
52 | const rootActivity: RootActivity = req.body | 56 | const rootActivity: RootActivity = req.body |
53 | let activities: Activity[] = [] | 57 | let activities: Activity[] |
54 | 58 | ||
55 | if ([ 'Collection', 'CollectionPage' ].indexOf(rootActivity.type) !== -1) { | 59 | if ([ 'Collection', 'CollectionPage' ].indexOf(rootActivity.type) !== -1) { |
56 | activities = (rootActivity as ActivityPubCollection).items | 60 | activities = (rootActivity as ActivityPubCollection).items |
diff --git a/server/controllers/api/accounts.ts b/server/controllers/api/accounts.ts index 05740318e..f354ccf24 100644 --- a/server/controllers/api/accounts.ts +++ b/server/controllers/api/accounts.ts | |||
@@ -16,21 +16,17 @@ import { | |||
16 | accountNameWithHostGetValidator, | 16 | accountNameWithHostGetValidator, |
17 | accountsSortValidator, | 17 | accountsSortValidator, |
18 | ensureAuthUserOwnsAccountValidator, | 18 | ensureAuthUserOwnsAccountValidator, |
19 | videosSortValidator, | 19 | videoChannelsSortValidator, |
20 | videoChannelsSortValidator | 20 | videosSortValidator |
21 | } from '../../middlewares/validators' | 21 | } from '../../middlewares/validators' |
22 | import { AccountModel } from '../../models/account/account' | 22 | import { AccountModel } from '../../models/account/account' |
23 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' | 23 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' |
24 | import { VideoModel } from '../../models/video/video' | 24 | import { VideoModel } from '../../models/video/video' |
25 | import { buildNSFWFilter, isUserAbleToSearchRemoteURI, getCountVideos } from '../../helpers/express-utils' | 25 | import { buildNSFWFilter, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' |
26 | import { VideoChannelModel } from '../../models/video/video-channel' | 26 | import { VideoChannelModel } from '../../models/video/video-channel' |
27 | import { JobQueue } from '../../lib/job-queue' | 27 | import { JobQueue } from '../../lib/job-queue' |
28 | import { logger } from '../../helpers/logger' | ||
29 | import { VideoPlaylistModel } from '../../models/video/video-playlist' | 28 | import { VideoPlaylistModel } from '../../models/video/video-playlist' |
30 | import { | 29 | import { commonVideoPlaylistFiltersValidator, videoPlaylistsSearchValidator } from '../../middlewares/validators/videos/video-playlists' |
31 | commonVideoPlaylistFiltersValidator, | ||
32 | videoPlaylistsSearchValidator | ||
33 | } from '../../middlewares/validators/videos/video-playlists' | ||
34 | 30 | ||
35 | const accountsRouter = express.Router() | 31 | const accountsRouter = express.Router() |
36 | 32 | ||
@@ -104,7 +100,6 @@ function getAccount (req: express.Request, res: express.Response) { | |||
104 | 100 | ||
105 | if (account.isOutdated()) { | 101 | if (account.isOutdated()) { |
106 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } }) | 102 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } }) |
107 | .catch(err => logger.error('Cannot create AP refresher job for actor %s.', account.Actor.url, { err })) | ||
108 | } | 103 | } |
109 | 104 | ||
110 | return res.json(account.toFormattedJSON()) | 105 | return res.json(account.toFormattedJSON()) |
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index ae4e00248..69940f395 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -31,12 +31,12 @@ configRouter.get('/', | |||
31 | configRouter.get('/custom', | 31 | configRouter.get('/custom', |
32 | authenticate, | 32 | authenticate, |
33 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), | 33 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), |
34 | asyncMiddleware(getCustomConfig) | 34 | getCustomConfig |
35 | ) | 35 | ) |
36 | configRouter.put('/custom', | 36 | configRouter.put('/custom', |
37 | authenticate, | 37 | authenticate, |
38 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), | 38 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), |
39 | asyncMiddleware(customConfigUpdateValidator), | 39 | customConfigUpdateValidator, |
40 | asyncMiddleware(updateCustomConfig) | 40 | asyncMiddleware(updateCustomConfig) |
41 | ) | 41 | ) |
42 | configRouter.delete('/custom', | 42 | configRouter.delete('/custom', |
@@ -196,7 +196,7 @@ function getAbout (req: express.Request, res: express.Response) { | |||
196 | return res.json(about).end() | 196 | return res.json(about).end() |
197 | } | 197 | } |
198 | 198 | ||
199 | async function getCustomConfig (req: express.Request, res: express.Response) { | 199 | function getCustomConfig (req: express.Request, res: express.Response) { |
200 | const data = customConfig() | 200 | const data = customConfig() |
201 | 201 | ||
202 | return res.json(data).end() | 202 | return res.json(data).end() |
@@ -250,7 +250,7 @@ function getRegisteredThemes () { | |||
250 | 250 | ||
251 | function getEnabledResolutions () { | 251 | function getEnabledResolutions () { |
252 | return Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) | 252 | return Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) |
253 | .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[ key ] === true) | 253 | .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[key] === true) |
254 | .map(r => parseInt(r, 10)) | 254 | .map(r => parseInt(r, 10)) |
255 | } | 255 | } |
256 | 256 | ||
@@ -340,13 +340,13 @@ function customConfig (): CustomConfig { | |||
340 | allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES, | 340 | allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES, |
341 | threads: CONFIG.TRANSCODING.THREADS, | 341 | threads: CONFIG.TRANSCODING.THREADS, |
342 | resolutions: { | 342 | resolutions: { |
343 | '0p': CONFIG.TRANSCODING.RESOLUTIONS[ '0p' ], | 343 | '0p': CONFIG.TRANSCODING.RESOLUTIONS['0p'], |
344 | '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ], | 344 | '240p': CONFIG.TRANSCODING.RESOLUTIONS['240p'], |
345 | '360p': CONFIG.TRANSCODING.RESOLUTIONS[ '360p' ], | 345 | '360p': CONFIG.TRANSCODING.RESOLUTIONS['360p'], |
346 | '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ], | 346 | '480p': CONFIG.TRANSCODING.RESOLUTIONS['480p'], |
347 | '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ], | 347 | '720p': CONFIG.TRANSCODING.RESOLUTIONS['720p'], |
348 | '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ], | 348 | '1080p': CONFIG.TRANSCODING.RESOLUTIONS['1080p'], |
349 | '2160p': CONFIG.TRANSCODING.RESOLUTIONS[ '2160p' ] | 349 | '2160p': CONFIG.TRANSCODING.RESOLUTIONS['2160p'] |
350 | }, | 350 | }, |
351 | webtorrent: { | 351 | webtorrent: { |
352 | enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED | 352 | enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED |
diff --git a/server/controllers/api/jobs.ts b/server/controllers/api/jobs.ts index 05320311e..13fc04d18 100644 --- a/server/controllers/api/jobs.ts +++ b/server/controllers/api/jobs.ts | |||
@@ -50,7 +50,7 @@ async function listJobs (req: express.Request, res: express.Response) { | |||
50 | }) | 50 | }) |
51 | const total = await JobQueue.Instance.count(state) | 51 | const total = await JobQueue.Instance.count(state) |
52 | 52 | ||
53 | const result: ResultList<any> = { | 53 | const result: ResultList<Job> = { |
54 | total, | 54 | total, |
55 | data: jobs.map(j => formatJob(j, state)) | 55 | data: jobs.map(j => formatJob(j, state)) |
56 | } | 56 | } |
diff --git a/server/controllers/api/overviews.ts b/server/controllers/api/overviews.ts index 46e76ac6b..75f3baedb 100644 --- a/server/controllers/api/overviews.ts +++ b/server/controllers/api/overviews.ts | |||
@@ -24,7 +24,7 @@ export { overviewsRouter } | |||
24 | const buildSamples = memoizee(async function () { | 24 | const buildSamples = memoizee(async function () { |
25 | const [ categories, channels, tags ] = await Promise.all([ | 25 | const [ categories, channels, tags ] = await Promise.all([ |
26 | VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), | 26 | VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), |
27 | VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD ,OVERVIEWS.VIDEOS.SAMPLES_COUNT), | 27 | VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), |
28 | TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT) | 28 | TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT) |
29 | ]) | 29 | ]) |
30 | 30 | ||
diff --git a/server/controllers/api/server/debug.ts b/server/controllers/api/server/debug.ts index 4450038f6..e12fc1dd4 100644 --- a/server/controllers/api/server/debug.ts +++ b/server/controllers/api/server/debug.ts | |||
@@ -1,13 +1,13 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { UserRight } from '../../../../shared/models/users' | 2 | import { UserRight } from '../../../../shared/models/users' |
3 | import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares' | 3 | import { authenticate, ensureUserHasRight } from '../../../middlewares' |
4 | 4 | ||
5 | const debugRouter = express.Router() | 5 | const debugRouter = express.Router() |
6 | 6 | ||
7 | debugRouter.get('/debug', | 7 | debugRouter.get('/debug', |
8 | authenticate, | 8 | authenticate, |
9 | ensureUserHasRight(UserRight.MANAGE_DEBUG), | 9 | ensureUserHasRight(UserRight.MANAGE_DEBUG), |
10 | asyncMiddleware(getDebug) | 10 | getDebug |
11 | ) | 11 | ) |
12 | 12 | ||
13 | // --------------------------------------------------------------------------- | 13 | // --------------------------------------------------------------------------- |
@@ -18,7 +18,7 @@ export { | |||
18 | 18 | ||
19 | // --------------------------------------------------------------------------- | 19 | // --------------------------------------------------------------------------- |
20 | 20 | ||
21 | async function getDebug (req: express.Request, res: express.Response) { | 21 | function getDebug (req: express.Request, res: express.Response) { |
22 | return res.json({ | 22 | return res.json({ |
23 | ip: req.ip | 23 | ip: req.ip |
24 | }).end() | 24 | }).end() |
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts index 29a403a43..0bc20bd60 100644 --- a/server/controllers/api/server/follows.ts +++ b/server/controllers/api/server/follows.ts | |||
@@ -24,7 +24,7 @@ import { | |||
24 | } from '../../../middlewares/validators' | 24 | } from '../../../middlewares/validators' |
25 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 25 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
26 | import { JobQueue } from '../../../lib/job-queue' | 26 | import { JobQueue } from '../../../lib/job-queue' |
27 | import { removeRedundancyOf } from '../../../lib/redundancy' | 27 | import { removeRedundanciesOfServer } from '../../../lib/redundancy' |
28 | import { sequelizeTypescript } from '../../../initializers/database' | 28 | import { sequelizeTypescript } from '../../../initializers/database' |
29 | import { autoFollowBackIfNeeded } from '../../../lib/activitypub/follow' | 29 | import { autoFollowBackIfNeeded } from '../../../lib/activitypub/follow' |
30 | 30 | ||
@@ -135,7 +135,6 @@ async function followInstance (req: express.Request, res: express.Response) { | |||
135 | } | 135 | } |
136 | 136 | ||
137 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) | 137 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) |
138 | .catch(err => logger.error('Cannot create follow job for %s.', host, err)) | ||
139 | } | 138 | } |
140 | 139 | ||
141 | return res.status(204).end() | 140 | return res.status(204).end() |
@@ -153,7 +152,7 @@ async function removeFollowing (req: express.Request, res: express.Response) { | |||
153 | await server.save({ transaction: t }) | 152 | await server.save({ transaction: t }) |
154 | 153 | ||
155 | // Async, could be long | 154 | // Async, could be long |
156 | removeRedundancyOf(server.id) | 155 | removeRedundanciesOfServer(server.id) |
157 | .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, err)) | 156 | .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, err)) |
158 | 157 | ||
159 | await follow.destroy({ transaction: t }) | 158 | await follow.destroy({ transaction: t }) |
diff --git a/server/controllers/api/server/logs.ts b/server/controllers/api/server/logs.ts index cd1e0f5bf..4b543d686 100644 --- a/server/controllers/api/server/logs.ts +++ b/server/controllers/api/server/logs.ts | |||
@@ -59,9 +59,9 @@ async function getLogs (req: express.Request, res: express.Response) { | |||
59 | } | 59 | } |
60 | 60 | ||
61 | async function generateOutput (options: { | 61 | async function generateOutput (options: { |
62 | startDateQuery: string, | 62 | startDateQuery: string |
63 | endDateQuery?: string, | 63 | endDateQuery?: string |
64 | level: LogLevel, | 64 | level: LogLevel |
65 | nameFilter: RegExp | 65 | nameFilter: RegExp |
66 | }) { | 66 | }) { |
67 | const { startDateQuery, level, nameFilter } = options | 67 | const { startDateQuery, level, nameFilter } = options |
@@ -111,7 +111,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date, | |||
111 | const output: any[] = [] | 111 | const output: any[] = [] |
112 | 112 | ||
113 | for (let i = lines.length - 1; i >= 0; i--) { | 113 | for (let i = lines.length - 1; i >= 0; i--) { |
114 | const line = lines[ i ] | 114 | const line = lines[i] |
115 | let log: any | 115 | let log: any |
116 | 116 | ||
117 | try { | 117 | try { |
@@ -122,7 +122,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date, | |||
122 | } | 122 | } |
123 | 123 | ||
124 | logTime = new Date(log.timestamp).getTime() | 124 | logTime = new Date(log.timestamp).getTime() |
125 | if (logTime >= startTime && logTime <= endTime && logsLevel[ log.level ] >= logsLevel[ level ]) { | 125 | if (logTime >= startTime && logTime <= endTime && logsLevel[log.level] >= logsLevel[level]) { |
126 | output.push(log) | 126 | output.push(log) |
127 | 127 | ||
128 | currentSize += line.length | 128 | currentSize += line.length |
diff --git a/server/controllers/api/server/redundancy.ts b/server/controllers/api/server/redundancy.ts index 4ea6164a3..1ced0759e 100644 --- a/server/controllers/api/server/redundancy.ts +++ b/server/controllers/api/server/redundancy.ts | |||
@@ -1,9 +1,24 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { UserRight } from '../../../../shared/models/users' | 2 | import { UserRight } from '../../../../shared/models/users' |
3 | import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares' | 3 | import { |
4 | import { updateServerRedundancyValidator } from '../../../middlewares/validators/redundancy' | 4 | asyncMiddleware, |
5 | import { removeRedundancyOf } from '../../../lib/redundancy' | 5 | authenticate, |
6 | ensureUserHasRight, | ||
7 | paginationValidator, | ||
8 | setDefaultPagination, | ||
9 | setDefaultVideoRedundanciesSort, | ||
10 | videoRedundanciesSortValidator | ||
11 | } from '../../../middlewares' | ||
12 | import { | ||
13 | listVideoRedundanciesValidator, | ||
14 | updateServerRedundancyValidator, | ||
15 | addVideoRedundancyValidator, | ||
16 | removeVideoRedundancyValidator | ||
17 | } from '../../../middlewares/validators/redundancy' | ||
18 | import { removeRedundanciesOfServer, removeVideoRedundancy } from '../../../lib/redundancy' | ||
6 | import { logger } from '../../../helpers/logger' | 19 | import { logger } from '../../../helpers/logger' |
20 | import { VideoRedundancyModel } from '@server/models/redundancy/video-redundancy' | ||
21 | import { JobQueue } from '@server/lib/job-queue' | ||
7 | 22 | ||
8 | const serverRedundancyRouter = express.Router() | 23 | const serverRedundancyRouter = express.Router() |
9 | 24 | ||
@@ -14,6 +29,31 @@ serverRedundancyRouter.put('/redundancy/:host', | |||
14 | asyncMiddleware(updateRedundancy) | 29 | asyncMiddleware(updateRedundancy) |
15 | ) | 30 | ) |
16 | 31 | ||
32 | serverRedundancyRouter.get('/redundancy/videos', | ||
33 | authenticate, | ||
34 | ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES), | ||
35 | listVideoRedundanciesValidator, | ||
36 | paginationValidator, | ||
37 | videoRedundanciesSortValidator, | ||
38 | setDefaultVideoRedundanciesSort, | ||
39 | setDefaultPagination, | ||
40 | asyncMiddleware(listVideoRedundancies) | ||
41 | ) | ||
42 | |||
43 | serverRedundancyRouter.post('/redundancy/videos', | ||
44 | authenticate, | ||
45 | ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES), | ||
46 | addVideoRedundancyValidator, | ||
47 | asyncMiddleware(addVideoRedundancy) | ||
48 | ) | ||
49 | |||
50 | serverRedundancyRouter.delete('/redundancy/videos/:redundancyId', | ||
51 | authenticate, | ||
52 | ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES), | ||
53 | removeVideoRedundancyValidator, | ||
54 | asyncMiddleware(removeVideoRedundancyController) | ||
55 | ) | ||
56 | |||
17 | // --------------------------------------------------------------------------- | 57 | // --------------------------------------------------------------------------- |
18 | 58 | ||
19 | export { | 59 | export { |
@@ -22,6 +62,42 @@ export { | |||
22 | 62 | ||
23 | // --------------------------------------------------------------------------- | 63 | // --------------------------------------------------------------------------- |
24 | 64 | ||
65 | async function listVideoRedundancies (req: express.Request, res: express.Response) { | ||
66 | const resultList = await VideoRedundancyModel.listForApi({ | ||
67 | start: req.query.start, | ||
68 | count: req.query.count, | ||
69 | sort: req.query.sort, | ||
70 | target: req.query.target, | ||
71 | strategy: req.query.strategy | ||
72 | }) | ||
73 | |||
74 | const result = { | ||
75 | total: resultList.total, | ||
76 | data: resultList.data.map(r => VideoRedundancyModel.toFormattedJSONStatic(r)) | ||
77 | } | ||
78 | |||
79 | return res.json(result) | ||
80 | } | ||
81 | |||
82 | async function addVideoRedundancy (req: express.Request, res: express.Response) { | ||
83 | const payload = { | ||
84 | videoId: res.locals.onlyVideo.id | ||
85 | } | ||
86 | |||
87 | await JobQueue.Instance.createJobWithPromise({ | ||
88 | type: 'video-redundancy', | ||
89 | payload | ||
90 | }) | ||
91 | |||
92 | return res.sendStatus(204) | ||
93 | } | ||
94 | |||
95 | async function removeVideoRedundancyController (req: express.Request, res: express.Response) { | ||
96 | await removeVideoRedundancy(res.locals.videoRedundancy) | ||
97 | |||
98 | return res.sendStatus(204) | ||
99 | } | ||
100 | |||
25 | async function updateRedundancy (req: express.Request, res: express.Response) { | 101 | async function updateRedundancy (req: express.Request, res: express.Response) { |
26 | const server = res.locals.server | 102 | const server = res.locals.server |
27 | 103 | ||
@@ -30,7 +106,7 @@ async function updateRedundancy (req: express.Request, res: express.Response) { | |||
30 | await server.save() | 106 | await server.save() |
31 | 107 | ||
32 | // Async, could be long | 108 | // Async, could be long |
33 | removeRedundancyOf(server.id) | 109 | removeRedundanciesOfServer(server.id) |
34 | .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, { err })) | 110 | .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, { err })) |
35 | 111 | ||
36 | return res.sendStatus(204) | 112 | return res.sendStatus(204) |
diff --git a/server/controllers/api/server/stats.ts b/server/controllers/api/server/stats.ts index 3616c074d..6d508a481 100644 --- a/server/controllers/api/server/stats.ts +++ b/server/controllers/api/server/stats.ts | |||
@@ -10,6 +10,7 @@ import { ROUTE_CACHE_LIFETIME } from '../../../initializers/constants' | |||
10 | import { cacheRoute } from '../../../middlewares/cache' | 10 | import { cacheRoute } from '../../../middlewares/cache' |
11 | import { VideoFileModel } from '../../../models/video/video-file' | 11 | import { VideoFileModel } from '../../../models/video/video-file' |
12 | import { CONFIG } from '../../../initializers/config' | 12 | import { CONFIG } from '../../../initializers/config' |
13 | import { VideoRedundancyStrategyWithManual } from '@shared/models' | ||
13 | 14 | ||
14 | const statsRouter = express.Router() | 15 | const statsRouter = express.Router() |
15 | 16 | ||
@@ -25,8 +26,15 @@ async function getStats (req: express.Request, res: express.Response) { | |||
25 | const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats() | 26 | const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats() |
26 | const { totalLocalVideoFilesSize } = await VideoFileModel.getStats() | 27 | const { totalLocalVideoFilesSize } = await VideoFileModel.getStats() |
27 | 28 | ||
29 | const strategies: { strategy: VideoRedundancyStrategyWithManual, size: number }[] = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES | ||
30 | .map(r => ({ | ||
31 | strategy: r.strategy, | ||
32 | size: r.size | ||
33 | })) | ||
34 | strategies.push({ strategy: 'manual', size: null }) | ||
35 | |||
28 | const videosRedundancyStats = await Promise.all( | 36 | const videosRedundancyStats = await Promise.all( |
29 | CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.map(r => { | 37 | strategies.map(r => { |
30 | return VideoRedundancyModel.getStats(r.strategy) | 38 | return VideoRedundancyModel.getStats(r.strategy) |
31 | .then(stats => Object.assign(stats, { strategy: r.strategy, totalSize: r.size })) | 39 | .then(stats => Object.assign(stats, { strategy: r.strategy, totalSize: r.size })) |
32 | }) | 40 | }) |
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index ac7c62aab..23890e20c 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts | |||
@@ -39,7 +39,7 @@ meRouter.get('/me', | |||
39 | ) | 39 | ) |
40 | meRouter.delete('/me', | 40 | meRouter.delete('/me', |
41 | authenticate, | 41 | authenticate, |
42 | asyncMiddleware(deleteMeValidator), | 42 | deleteMeValidator, |
43 | asyncMiddleware(deleteMe) | 43 | asyncMiddleware(deleteMe) |
44 | ) | 44 | ) |
45 | 45 | ||
@@ -214,7 +214,7 @@ async function updateMe (req: express.Request, res: express.Response) { | |||
214 | } | 214 | } |
215 | 215 | ||
216 | async function updateMyAvatar (req: express.Request, res: express.Response) { | 216 | async function updateMyAvatar (req: express.Request, res: express.Response) { |
217 | const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ] | 217 | const avatarPhysicalFile = req.files['avatarfile'][0] |
218 | const user = res.locals.oauth.token.user | 218 | const user = res.locals.oauth.token.user |
219 | 219 | ||
220 | const userAccount = await AccountModel.load(user.Account.id) | 220 | const userAccount = await AccountModel.load(user.Account.id) |
diff --git a/server/controllers/api/users/my-subscriptions.ts b/server/controllers/api/users/my-subscriptions.ts index 43c4c37d8..888392b8b 100644 --- a/server/controllers/api/users/my-subscriptions.ts +++ b/server/controllers/api/users/my-subscriptions.ts | |||
@@ -19,7 +19,6 @@ import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils' | |||
19 | import { VideoFilter } from '../../../../shared/models/videos/video-query.type' | 19 | import { VideoFilter } from '../../../../shared/models/videos/video-query.type' |
20 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 20 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
21 | import { JobQueue } from '../../../lib/job-queue' | 21 | import { JobQueue } from '../../../lib/job-queue' |
22 | import { logger } from '../../../helpers/logger' | ||
23 | import { sequelizeTypescript } from '../../../initializers/database' | 22 | import { sequelizeTypescript } from '../../../initializers/database' |
24 | 23 | ||
25 | const mySubscriptionsRouter = express.Router() | 24 | const mySubscriptionsRouter = express.Router() |
@@ -52,7 +51,7 @@ mySubscriptionsRouter.get('/me/subscriptions', | |||
52 | mySubscriptionsRouter.post('/me/subscriptions', | 51 | mySubscriptionsRouter.post('/me/subscriptions', |
53 | authenticate, | 52 | authenticate, |
54 | userSubscriptionAddValidator, | 53 | userSubscriptionAddValidator, |
55 | asyncMiddleware(addUserSubscription) | 54 | addUserSubscription |
56 | ) | 55 | ) |
57 | 56 | ||
58 | mySubscriptionsRouter.get('/me/subscriptions/:uri', | 57 | mySubscriptionsRouter.get('/me/subscriptions/:uri', |
@@ -106,7 +105,7 @@ async function areSubscriptionsExist (req: express.Request, res: express.Respons | |||
106 | return res.json(existObject) | 105 | return res.json(existObject) |
107 | } | 106 | } |
108 | 107 | ||
109 | async function addUserSubscription (req: express.Request, res: express.Response) { | 108 | function addUserSubscription (req: express.Request, res: express.Response) { |
110 | const user = res.locals.oauth.token.User | 109 | const user = res.locals.oauth.token.User |
111 | const [ name, host ] = req.body.uri.split('@') | 110 | const [ name, host ] = req.body.uri.split('@') |
112 | 111 | ||
@@ -117,7 +116,6 @@ async function addUserSubscription (req: express.Request, res: express.Response) | |||
117 | } | 116 | } |
118 | 117 | ||
119 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) | 118 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) |
120 | .catch(err => logger.error('Cannot create follow job for subscription %s.', req.body.uri, err)) | ||
121 | 119 | ||
122 | return res.status(204).end() | 120 | return res.status(204).end() |
123 | } | 121 | } |
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index e1f37a8fb..a808896ff 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts | |||
@@ -119,7 +119,7 @@ async function listVideoChannels (req: express.Request, res: express.Response) { | |||
119 | } | 119 | } |
120 | 120 | ||
121 | async function updateVideoChannelAvatar (req: express.Request, res: express.Response) { | 121 | async function updateVideoChannelAvatar (req: express.Request, res: express.Response) { |
122 | const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ] | 122 | const avatarPhysicalFile = req.files['avatarfile'][0] |
123 | const videoChannel = res.locals.videoChannel | 123 | const videoChannel = res.locals.videoChannel |
124 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON()) | 124 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON()) |
125 | 125 | ||
@@ -232,7 +232,6 @@ async function getVideoChannel (req: express.Request, res: express.Response) { | |||
232 | 232 | ||
233 | if (videoChannelWithVideos.isOutdated()) { | 233 | if (videoChannelWithVideos.isOutdated()) { |
234 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } }) | 234 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } }) |
235 | .catch(err => logger.error('Cannot create AP refresher job for actor %s.', videoChannelWithVideos.Actor.url, { err })) | ||
236 | } | 235 | } |
237 | 236 | ||
238 | return res.json(videoChannelWithVideos.toFormattedJSON()) | 237 | return res.json(videoChannelWithVideos.toFormattedJSON()) |
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts index d9f0ff925..b51490bf9 100644 --- a/server/controllers/api/video-playlist.ts +++ b/server/controllers/api/video-playlist.ts | |||
@@ -144,7 +144,6 @@ function getVideoPlaylist (req: express.Request, res: express.Response) { | |||
144 | 144 | ||
145 | if (videoPlaylist.isOutdated()) { | 145 | if (videoPlaylist.isOutdated()) { |
146 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: videoPlaylist.url } }) | 146 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: videoPlaylist.url } }) |
147 | .catch(err => logger.error('Cannot create AP refresher job for playlist %s.', videoPlaylist.url, { err })) | ||
148 | } | 147 | } |
149 | 148 | ||
150 | return res.json(videoPlaylist.toFormattedJSON()) | 149 | return res.json(videoPlaylist.toFormattedJSON()) |
diff --git a/server/controllers/api/videos/captions.ts b/server/controllers/api/videos/captions.ts index 37481d12f..fd7b165fb 100644 --- a/server/controllers/api/videos/captions.ts +++ b/server/controllers/api/videos/captions.ts | |||
@@ -66,7 +66,7 @@ async function addVideoCaption (req: express.Request, res: express.Response) { | |||
66 | await moveAndProcessCaptionFile(videoCaptionPhysicalFile, videoCaption) | 66 | await moveAndProcessCaptionFile(videoCaptionPhysicalFile, videoCaption) |
67 | 67 | ||
68 | await sequelizeTypescript.transaction(async t => { | 68 | await sequelizeTypescript.transaction(async t => { |
69 | await VideoCaptionModel.insertOrReplaceLanguage(video.id, req.params.captionLanguage, t) | 69 | await VideoCaptionModel.insertOrReplaceLanguage(video.id, req.params.captionLanguage, null, t) |
70 | 70 | ||
71 | // Update video update | 71 | // Update video update |
72 | await federateVideoIfNeeded(video, false, t) | 72 | await federateVideoIfNeeded(video, false, t) |
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index 28ced5836..ed223cbc9 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts | |||
@@ -88,12 +88,12 @@ async function addTorrentImport (req: express.Request, res: express.Response, to | |||
88 | const buf = await readFile(torrentfile.path) | 88 | const buf = await readFile(torrentfile.path) |
89 | const parsedTorrent = parseTorrent(buf) | 89 | const parsedTorrent = parseTorrent(buf) |
90 | 90 | ||
91 | videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[ 0 ] : parsedTorrent.name as string | 91 | videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[0] : parsedTorrent.name as string |
92 | } else { | 92 | } else { |
93 | magnetUri = body.magnetUri | 93 | magnetUri = body.magnetUri |
94 | 94 | ||
95 | const parsed = magnetUtil.decode(magnetUri) | 95 | const parsed = magnetUtil.decode(magnetUri) |
96 | videoName = isArray(parsed.name) ? parsed.name[ 0 ] : parsed.name as string | 96 | videoName = isArray(parsed.name) ? parsed.name[0] : parsed.name as string |
97 | } | 97 | } |
98 | 98 | ||
99 | const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName }) | 99 | const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName }) |
@@ -124,7 +124,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to | |||
124 | videoImportId: videoImport.id, | 124 | videoImportId: videoImport.id, |
125 | magnetUri | 125 | magnetUri |
126 | } | 126 | } |
127 | await JobQueue.Instance.createJob({ type: 'video-import', payload }) | 127 | await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload }) |
128 | 128 | ||
129 | auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) | 129 | auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) |
130 | 130 | ||
@@ -176,7 +176,7 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response) | |||
176 | downloadThumbnail: !thumbnailModel, | 176 | downloadThumbnail: !thumbnailModel, |
177 | downloadPreview: !previewModel | 177 | downloadPreview: !previewModel |
178 | } | 178 | } |
179 | await JobQueue.Instance.createJob({ type: 'video-import', payload }) | 179 | await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload }) |
180 | 180 | ||
181 | auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) | 181 | auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) |
182 | 182 | ||
@@ -211,7 +211,7 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You | |||
211 | async function processThumbnail (req: express.Request, video: VideoModel) { | 211 | async function processThumbnail (req: express.Request, video: VideoModel) { |
212 | const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined | 212 | const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined |
213 | if (thumbnailField) { | 213 | if (thumbnailField) { |
214 | const thumbnailPhysicalFile = thumbnailField[ 0 ] | 214 | const thumbnailPhysicalFile = thumbnailField[0] |
215 | 215 | ||
216 | return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false) | 216 | return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false) |
217 | } | 217 | } |
@@ -231,12 +231,12 @@ async function processPreview (req: express.Request, video: VideoModel) { | |||
231 | } | 231 | } |
232 | 232 | ||
233 | function insertIntoDB (parameters: { | 233 | function insertIntoDB (parameters: { |
234 | video: MVideoThumbnailAccountDefault, | 234 | video: MVideoThumbnailAccountDefault |
235 | thumbnailModel: MThumbnail, | 235 | thumbnailModel: MThumbnail |
236 | previewModel: MThumbnail, | 236 | previewModel: MThumbnail |
237 | videoChannel: MChannelAccountDefault, | 237 | videoChannel: MChannelAccountDefault |
238 | tags: string[], | 238 | tags: string[] |
239 | videoImportAttributes: Partial<MVideoImport>, | 239 | videoImportAttributes: Partial<MVideoImport> |
240 | user: MUser | 240 | user: MUser |
241 | }): Bluebird<MVideoImportFormattable> { | 241 | }): Bluebird<MVideoImportFormattable> { |
242 | const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters | 242 | const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters |
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 8d4ff07eb..1d61f8427 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -307,7 +307,7 @@ async function addVideo (req: express.Request, res: express.Response) { | |||
307 | } | 307 | } |
308 | } | 308 | } |
309 | 309 | ||
310 | await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) | 310 | await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: dataInput }) |
311 | } | 311 | } |
312 | 312 | ||
313 | Hooks.runAction('action:api.video.uploaded', { video: videoCreated }) | 313 | Hooks.runAction('action:api.video.uploaded', { video: videoCreated }) |
@@ -452,7 +452,6 @@ async function getVideo (req: express.Request, res: express.Response) { | |||
452 | 452 | ||
453 | if (video.isOutdated()) { | 453 | if (video.isOutdated()) { |
454 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } }) | 454 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } }) |
455 | .catch(err => logger.error('Cannot create AP refresher job for video %s.', video.url, { err })) | ||
456 | } | 455 | } |
457 | 456 | ||
458 | return res.json(video.toFormattedDetailsJSON()) | 457 | return res.json(video.toFormattedDetailsJSON()) |
diff --git a/server/controllers/client.ts b/server/controllers/client.ts index dc3ff18fc..e4643e171 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts | |||
@@ -66,7 +66,7 @@ export { | |||
66 | 66 | ||
67 | // --------------------------------------------------------------------------- | 67 | // --------------------------------------------------------------------------- |
68 | 68 | ||
69 | async function serveServerTranslations (req: express.Request, res: express.Response) { | 69 | function serveServerTranslations (req: express.Request, res: express.Response) { |
70 | const locale = req.params.locale | 70 | const locale = req.params.locale |
71 | const file = req.params.file | 71 | const file = req.params.file |
72 | 72 | ||
diff --git a/server/controllers/static.ts b/server/controllers/static.ts index a4bb3a4d9..4c6cf9597 100644 --- a/server/controllers/static.ts +++ b/server/controllers/static.ts | |||
@@ -45,12 +45,12 @@ staticRouter.use( | |||
45 | staticRouter.use( | 45 | staticRouter.use( |
46 | STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent', | 46 | STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent', |
47 | asyncMiddleware(videosDownloadValidator), | 47 | asyncMiddleware(videosDownloadValidator), |
48 | asyncMiddleware(downloadTorrent) | 48 | downloadTorrent |
49 | ) | 49 | ) |
50 | staticRouter.use( | 50 | staticRouter.use( |
51 | STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent', | 51 | STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent', |
52 | asyncMiddleware(videosDownloadValidator), | 52 | asyncMiddleware(videosDownloadValidator), |
53 | asyncMiddleware(downloadHLSVideoFileTorrent) | 53 | downloadHLSVideoFileTorrent |
54 | ) | 54 | ) |
55 | 55 | ||
56 | // Videos path for webseeding | 56 | // Videos path for webseeding |
@@ -68,13 +68,13 @@ staticRouter.use( | |||
68 | staticRouter.use( | 68 | staticRouter.use( |
69 | STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension', | 69 | STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension', |
70 | asyncMiddleware(videosDownloadValidator), | 70 | asyncMiddleware(videosDownloadValidator), |
71 | asyncMiddleware(downloadVideoFile) | 71 | downloadVideoFile |
72 | ) | 72 | ) |
73 | 73 | ||
74 | staticRouter.use( | 74 | staticRouter.use( |
75 | STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension', | 75 | STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension', |
76 | asyncMiddleware(videosDownloadValidator), | 76 | asyncMiddleware(videosDownloadValidator), |
77 | asyncMiddleware(downloadHLSVideoFile) | 77 | downloadHLSVideoFile |
78 | ) | 78 | ) |
79 | 79 | ||
80 | // HLS | 80 | // HLS |
@@ -325,7 +325,7 @@ async function generateNodeinfo (req: express.Request, res: express.Response) { | |||
325 | return res.send(json).end() | 325 | return res.send(json).end() |
326 | } | 326 | } |
327 | 327 | ||
328 | async function downloadTorrent (req: express.Request, res: express.Response) { | 328 | function downloadTorrent (req: express.Request, res: express.Response) { |
329 | const video = res.locals.videoAll | 329 | const video = res.locals.videoAll |
330 | 330 | ||
331 | const videoFile = getVideoFile(req, video.VideoFiles) | 331 | const videoFile = getVideoFile(req, video.VideoFiles) |
@@ -334,7 +334,7 @@ async function downloadTorrent (req: express.Request, res: express.Response) { | |||
334 | return res.download(getTorrentFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p.torrent`) | 334 | return res.download(getTorrentFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p.torrent`) |
335 | } | 335 | } |
336 | 336 | ||
337 | async function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) { | 337 | function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) { |
338 | const video = res.locals.videoAll | 338 | const video = res.locals.videoAll |
339 | 339 | ||
340 | const playlist = getHLSPlaylist(video) | 340 | const playlist = getHLSPlaylist(video) |
@@ -346,7 +346,7 @@ async function downloadHLSVideoFileTorrent (req: express.Request, res: express.R | |||
346 | return res.download(getTorrentFilePath(playlist, videoFile), `${video.name}-${videoFile.resolution}p-hls.torrent`) | 346 | return res.download(getTorrentFilePath(playlist, videoFile), `${video.name}-${videoFile.resolution}p-hls.torrent`) |
347 | } | 347 | } |
348 | 348 | ||
349 | async function downloadVideoFile (req: express.Request, res: express.Response) { | 349 | function downloadVideoFile (req: express.Request, res: express.Response) { |
350 | const video = res.locals.videoAll | 350 | const video = res.locals.videoAll |
351 | 351 | ||
352 | const videoFile = getVideoFile(req, video.VideoFiles) | 352 | const videoFile = getVideoFile(req, video.VideoFiles) |
@@ -355,7 +355,7 @@ async function downloadVideoFile (req: express.Request, res: express.Response) { | |||
355 | return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`) | 355 | return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`) |
356 | } | 356 | } |
357 | 357 | ||
358 | async function downloadHLSVideoFile (req: express.Request, res: express.Response) { | 358 | function downloadHLSVideoFile (req: express.Request, res: express.Response) { |
359 | const video = res.locals.videoAll | 359 | const video = res.locals.videoAll |
360 | const playlist = getHLSPlaylist(video) | 360 | const playlist = getHLSPlaylist(video) |
361 | if (!playlist) return res.status(404).end | 361 | if (!playlist) return res.status(404).end |
diff --git a/server/controllers/tracker.ts b/server/controllers/tracker.ts index 2ae1cf86c..e9c8a13da 100644 --- a/server/controllers/tracker.ts +++ b/server/controllers/tracker.ts | |||
@@ -6,7 +6,6 @@ import * as proxyAddr from 'proxy-addr' | |||
6 | import { Server as WebSocketServer } from 'ws' | 6 | import { Server as WebSocketServer } from 'ws' |
7 | import { TRACKER_RATE_LIMITS } from '../initializers/constants' | 7 | import { TRACKER_RATE_LIMITS } from '../initializers/constants' |
8 | import { VideoFileModel } from '../models/video/video-file' | 8 | import { VideoFileModel } from '../models/video/video-file' |
9 | import { parse } from 'url' | ||
10 | import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' | 9 | import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' |
11 | import { CONFIG } from '../initializers/config' | 10 | import { CONFIG } from '../initializers/config' |
12 | 11 | ||
@@ -38,11 +37,11 @@ const trackerServer = new TrackerServer({ | |||
38 | 37 | ||
39 | const key = ip + '-' + infoHash | 38 | const key = ip + '-' + infoHash |
40 | 39 | ||
41 | peersIps[ ip ] = peersIps[ ip ] ? peersIps[ ip ] + 1 : 1 | 40 | peersIps[ip] = peersIps[ip] ? peersIps[ip] + 1 : 1 |
42 | peersIpInfoHash[ key ] = peersIpInfoHash[ key ] ? peersIpInfoHash[ key ] + 1 : 1 | 41 | peersIpInfoHash[key] = peersIpInfoHash[key] ? peersIpInfoHash[key] + 1 : 1 |
43 | 42 | ||
44 | if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[ key ] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) { | 43 | if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[key] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) { |
45 | return cb(new Error(`Too many requests (${peersIpInfoHash[ key ]} of ip ${ip} for torrent ${infoHash}`)) | 44 | return cb(new Error(`Too many requests (${peersIpInfoHash[key]} of ip ${ip} for torrent ${infoHash}`)) |
46 | } | 45 | } |
47 | 46 | ||
48 | try { | 47 | try { |
@@ -87,10 +86,8 @@ function createWebsocketTrackerServer (app: express.Application) { | |||
87 | trackerServer.onWebSocketConnection(ws) | 86 | trackerServer.onWebSocketConnection(ws) |
88 | }) | 87 | }) |
89 | 88 | ||
90 | server.on('upgrade', (request, socket, head) => { | 89 | server.on('upgrade', (request: express.Request, socket, head) => { |
91 | const pathname = parse(request.url).pathname | 90 | if (request.path === '/tracker/socket') { |
92 | |||
93 | if (pathname === '/tracker/socket') { | ||
94 | wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request)) | 91 | wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request)) |
95 | } | 92 | } |
96 | 93 | ||
diff --git a/server/controllers/webfinger.ts b/server/controllers/webfinger.ts index fc9575160..77c851880 100644 --- a/server/controllers/webfinger.ts +++ b/server/controllers/webfinger.ts | |||
@@ -18,7 +18,7 @@ export { | |||
18 | // --------------------------------------------------------------------------- | 18 | // --------------------------------------------------------------------------- |
19 | 19 | ||
20 | function webfingerController (req: express.Request, res: express.Response) { | 20 | function webfingerController (req: express.Request, res: express.Response) { |
21 | const actor = res.locals.actorFull | 21 | const actor = res.locals.actorUrl |
22 | 22 | ||
23 | const json = { | 23 | const json = { |
24 | subject: req.query.resource, | 24 | subject: req.query.resource, |
@@ -32,5 +32,5 @@ function webfingerController (req: express.Request, res: express.Response) { | |||
32 | ] | 32 | ] |
33 | } | 33 | } |
34 | 34 | ||
35 | return res.json(json).end() | 35 | return res.json(json) |
36 | } | 36 | } |
diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts index 239d8291d..326785b68 100644 --- a/server/helpers/activitypub.ts +++ b/server/helpers/activitypub.ts | |||
@@ -2,99 +2,106 @@ import * as Bluebird from 'bluebird' | |||
2 | import validator from 'validator' | 2 | import validator from 'validator' |
3 | import { ResultList } from '../../shared/models' | 3 | import { ResultList } from '../../shared/models' |
4 | import { Activity } from '../../shared/models/activitypub' | 4 | import { Activity } from '../../shared/models/activitypub' |
5 | import { ACTIVITY_PUB } from '../initializers/constants' | 5 | import { ACTIVITY_PUB, REMOTE_SCHEME } from '../initializers/constants' |
6 | import { signJsonLDObject } from './peertube-crypto' | 6 | import { signJsonLDObject } from './peertube-crypto' |
7 | import { pageToStartAndCount } from './core-utils' | 7 | import { pageToStartAndCount } from './core-utils' |
8 | import { parse } from 'url' | 8 | import { URL } from 'url' |
9 | import { MActor } from '../typings/models' | 9 | import { MActor, MVideoAccountLight } from '../typings/models' |
10 | 10 | ||
11 | function activityPubContextify <T> (data: T) { | 11 | export type ContextType = 'All' | 'View' | 'Announce' |
12 | return Object.assign(data, { | 12 | |
13 | function activityPubContextify <T> (data: T, type: ContextType = 'All') { | ||
14 | const base = { | ||
15 | RsaSignature2017: 'https://w3id.org/security#RsaSignature2017' | ||
16 | } | ||
17 | |||
18 | if (type === 'All') { | ||
19 | Object.assign(base, { | ||
20 | pt: 'https://joinpeertube.org/ns#', | ||
21 | sc: 'http://schema.org#', | ||
22 | Hashtag: 'as:Hashtag', | ||
23 | uuid: 'sc:identifier', | ||
24 | category: 'sc:category', | ||
25 | licence: 'sc:license', | ||
26 | subtitleLanguage: 'sc:subtitleLanguage', | ||
27 | sensitive: 'as:sensitive', | ||
28 | language: 'sc:inLanguage', | ||
29 | expires: 'sc:expires', | ||
30 | CacheFile: 'pt:CacheFile', | ||
31 | Infohash: 'pt:Infohash', | ||
32 | originallyPublishedAt: 'sc:datePublished', | ||
33 | views: { | ||
34 | '@type': 'sc:Number', | ||
35 | '@id': 'pt:views' | ||
36 | }, | ||
37 | state: { | ||
38 | '@type': 'sc:Number', | ||
39 | '@id': 'pt:state' | ||
40 | }, | ||
41 | size: { | ||
42 | '@type': 'sc:Number', | ||
43 | '@id': 'pt:size' | ||
44 | }, | ||
45 | fps: { | ||
46 | '@type': 'sc:Number', | ||
47 | '@id': 'pt:fps' | ||
48 | }, | ||
49 | startTimestamp: { | ||
50 | '@type': 'sc:Number', | ||
51 | '@id': 'pt:startTimestamp' | ||
52 | }, | ||
53 | stopTimestamp: { | ||
54 | '@type': 'sc:Number', | ||
55 | '@id': 'pt:stopTimestamp' | ||
56 | }, | ||
57 | position: { | ||
58 | '@type': 'sc:Number', | ||
59 | '@id': 'pt:position' | ||
60 | }, | ||
61 | commentsEnabled: { | ||
62 | '@type': 'sc:Boolean', | ||
63 | '@id': 'pt:commentsEnabled' | ||
64 | }, | ||
65 | downloadEnabled: { | ||
66 | '@type': 'sc:Boolean', | ||
67 | '@id': 'pt:downloadEnabled' | ||
68 | }, | ||
69 | waitTranscoding: { | ||
70 | '@type': 'sc:Boolean', | ||
71 | '@id': 'pt:waitTranscoding' | ||
72 | }, | ||
73 | support: { | ||
74 | '@type': 'sc:Text', | ||
75 | '@id': 'pt:support' | ||
76 | }, | ||
77 | likes: { | ||
78 | '@id': 'as:likes', | ||
79 | '@type': '@id' | ||
80 | }, | ||
81 | dislikes: { | ||
82 | '@id': 'as:dislikes', | ||
83 | '@type': '@id' | ||
84 | }, | ||
85 | playlists: { | ||
86 | '@id': 'pt:playlists', | ||
87 | '@type': '@id' | ||
88 | }, | ||
89 | shares: { | ||
90 | '@id': 'as:shares', | ||
91 | '@type': '@id' | ||
92 | }, | ||
93 | comments: { | ||
94 | '@id': 'as:comments', | ||
95 | '@type': '@id' | ||
96 | } | ||
97 | }) | ||
98 | } | ||
99 | |||
100 | return Object.assign({}, data, { | ||
13 | '@context': [ | 101 | '@context': [ |
14 | 'https://www.w3.org/ns/activitystreams', | 102 | 'https://www.w3.org/ns/activitystreams', |
15 | 'https://w3id.org/security/v1', | 103 | 'https://w3id.org/security/v1', |
16 | { | 104 | base |
17 | RsaSignature2017: 'https://w3id.org/security#RsaSignature2017', | ||
18 | pt: 'https://joinpeertube.org/ns#', | ||
19 | sc: 'http://schema.org#', | ||
20 | Hashtag: 'as:Hashtag', | ||
21 | uuid: 'sc:identifier', | ||
22 | category: 'sc:category', | ||
23 | licence: 'sc:license', | ||
24 | subtitleLanguage: 'sc:subtitleLanguage', | ||
25 | sensitive: 'as:sensitive', | ||
26 | language: 'sc:inLanguage', | ||
27 | expires: 'sc:expires', | ||
28 | CacheFile: 'pt:CacheFile', | ||
29 | Infohash: 'pt:Infohash', | ||
30 | originallyPublishedAt: 'sc:datePublished', | ||
31 | views: { | ||
32 | '@type': 'sc:Number', | ||
33 | '@id': 'pt:views' | ||
34 | }, | ||
35 | state: { | ||
36 | '@type': 'sc:Number', | ||
37 | '@id': 'pt:state' | ||
38 | }, | ||
39 | size: { | ||
40 | '@type': 'sc:Number', | ||
41 | '@id': 'pt:size' | ||
42 | }, | ||
43 | fps: { | ||
44 | '@type': 'sc:Number', | ||
45 | '@id': 'pt:fps' | ||
46 | }, | ||
47 | startTimestamp: { | ||
48 | '@type': 'sc:Number', | ||
49 | '@id': 'pt:startTimestamp' | ||
50 | }, | ||
51 | stopTimestamp: { | ||
52 | '@type': 'sc:Number', | ||
53 | '@id': 'pt:stopTimestamp' | ||
54 | }, | ||
55 | position: { | ||
56 | '@type': 'sc:Number', | ||
57 | '@id': 'pt:position' | ||
58 | }, | ||
59 | commentsEnabled: { | ||
60 | '@type': 'sc:Boolean', | ||
61 | '@id': 'pt:commentsEnabled' | ||
62 | }, | ||
63 | downloadEnabled: { | ||
64 | '@type': 'sc:Boolean', | ||
65 | '@id': 'pt:downloadEnabled' | ||
66 | }, | ||
67 | waitTranscoding: { | ||
68 | '@type': 'sc:Boolean', | ||
69 | '@id': 'pt:waitTranscoding' | ||
70 | }, | ||
71 | support: { | ||
72 | '@type': 'sc:Text', | ||
73 | '@id': 'pt:support' | ||
74 | } | ||
75 | }, | ||
76 | { | ||
77 | likes: { | ||
78 | '@id': 'as:likes', | ||
79 | '@type': '@id' | ||
80 | }, | ||
81 | dislikes: { | ||
82 | '@id': 'as:dislikes', | ||
83 | '@type': '@id' | ||
84 | }, | ||
85 | playlists: { | ||
86 | '@id': 'pt:playlists', | ||
87 | '@type': '@id' | ||
88 | }, | ||
89 | shares: { | ||
90 | '@id': 'as:shares', | ||
91 | '@type': '@id' | ||
92 | }, | ||
93 | comments: { | ||
94 | '@id': 'as:comments', | ||
95 | '@type': '@id' | ||
96 | } | ||
97 | } | ||
98 | ] | 105 | ] |
99 | }) | 106 | }) |
100 | } | 107 | } |
@@ -148,8 +155,8 @@ async function activityPubCollectionPagination ( | |||
148 | 155 | ||
149 | } | 156 | } |
150 | 157 | ||
151 | function buildSignedActivity (byActor: MActor, data: Object) { | 158 | function buildSignedActivity (byActor: MActor, data: Object, contextType?: ContextType) { |
152 | const activity = activityPubContextify(data) | 159 | const activity = activityPubContextify(data, contextType) |
153 | 160 | ||
154 | return signJsonLDObject(byActor, activity) as Promise<Activity> | 161 | return signJsonLDObject(byActor, activity) as Promise<Activity> |
155 | } | 162 | } |
@@ -161,12 +168,18 @@ function getAPId (activity: string | { id: string }) { | |||
161 | } | 168 | } |
162 | 169 | ||
163 | function checkUrlsSameHost (url1: string, url2: string) { | 170 | function checkUrlsSameHost (url1: string, url2: string) { |
164 | const idHost = parse(url1).host | 171 | const idHost = new URL(url1).host |
165 | const actorHost = parse(url2).host | 172 | const actorHost = new URL(url2).host |
166 | 173 | ||
167 | return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase() | 174 | return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase() |
168 | } | 175 | } |
169 | 176 | ||
177 | function buildRemoteVideoBaseUrl (video: MVideoAccountLight, path: string) { | ||
178 | const host = video.VideoChannel.Account.Actor.Server.host | ||
179 | |||
180 | return REMOTE_SCHEME.HTTP + '://' + host + path | ||
181 | } | ||
182 | |||
170 | // --------------------------------------------------------------------------- | 183 | // --------------------------------------------------------------------------- |
171 | 184 | ||
172 | export { | 185 | export { |
@@ -174,5 +187,6 @@ export { | |||
174 | getAPId, | 187 | getAPId, |
175 | activityPubContextify, | 188 | activityPubContextify, |
176 | activityPubCollectionPagination, | 189 | activityPubCollectionPagination, |
177 | buildSignedActivity | 190 | buildSignedActivity, |
191 | buildRemoteVideoBaseUrl | ||
178 | } | 192 | } |
diff --git a/server/helpers/audit-logger.ts b/server/helpers/audit-logger.ts index 9b258dc3a..a4cfeef76 100644 --- a/server/helpers/audit-logger.ts +++ b/server/helpers/audit-logger.ts | |||
@@ -81,7 +81,8 @@ function auditLoggerFactory (domain: string) { | |||
81 | } | 81 | } |
82 | 82 | ||
83 | abstract class EntityAuditView { | 83 | abstract class EntityAuditView { |
84 | constructor (private keysToKeep: Array<string>, private prefix: string, private entityInfos: object) { } | 84 | constructor (private readonly keysToKeep: string[], private readonly prefix: string, private readonly entityInfos: object) { } |
85 | |||
85 | toLogKeys (): object { | 86 | toLogKeys (): object { |
86 | return chain(flatten(this.entityInfos, { delimiter: '-', safe: true })) | 87 | return chain(flatten(this.entityInfos, { delimiter: '-', safe: true })) |
87 | .pick(this.keysToKeep) | 88 | .pick(this.keysToKeep) |
@@ -121,7 +122,7 @@ const videoKeysToKeep = [ | |||
121 | 'downloadEnabled' | 122 | 'downloadEnabled' |
122 | ] | 123 | ] |
123 | class VideoAuditView extends EntityAuditView { | 124 | class VideoAuditView extends EntityAuditView { |
124 | constructor (private video: VideoDetails) { | 125 | constructor (private readonly video: VideoDetails) { |
125 | super(videoKeysToKeep, 'video', video) | 126 | super(videoKeysToKeep, 'video', video) |
126 | } | 127 | } |
127 | } | 128 | } |
@@ -132,7 +133,7 @@ const videoImportKeysToKeep = [ | |||
132 | 'video-name' | 133 | 'video-name' |
133 | ] | 134 | ] |
134 | class VideoImportAuditView extends EntityAuditView { | 135 | class VideoImportAuditView extends EntityAuditView { |
135 | constructor (private videoImport: VideoImport) { | 136 | constructor (private readonly videoImport: VideoImport) { |
136 | super(videoImportKeysToKeep, 'video-import', videoImport) | 137 | super(videoImportKeysToKeep, 'video-import', videoImport) |
137 | } | 138 | } |
138 | } | 139 | } |
@@ -151,7 +152,7 @@ const commentKeysToKeep = [ | |||
151 | 'account-name' | 152 | 'account-name' |
152 | ] | 153 | ] |
153 | class CommentAuditView extends EntityAuditView { | 154 | class CommentAuditView extends EntityAuditView { |
154 | constructor (private comment: VideoComment) { | 155 | constructor (private readonly comment: VideoComment) { |
155 | super(commentKeysToKeep, 'comment', comment) | 156 | super(commentKeysToKeep, 'comment', comment) |
156 | } | 157 | } |
157 | } | 158 | } |
@@ -180,7 +181,7 @@ const userKeysToKeep = [ | |||
180 | 'videoChannels' | 181 | 'videoChannels' |
181 | ] | 182 | ] |
182 | class UserAuditView extends EntityAuditView { | 183 | class UserAuditView extends EntityAuditView { |
183 | constructor (private user: User) { | 184 | constructor (private readonly user: User) { |
184 | super(userKeysToKeep, 'user', user) | 185 | super(userKeysToKeep, 'user', user) |
185 | } | 186 | } |
186 | } | 187 | } |
@@ -206,7 +207,7 @@ const channelKeysToKeep = [ | |||
206 | 'ownerAccount-displayedName' | 207 | 'ownerAccount-displayedName' |
207 | ] | 208 | ] |
208 | class VideoChannelAuditView extends EntityAuditView { | 209 | class VideoChannelAuditView extends EntityAuditView { |
209 | constructor (private channel: VideoChannel) { | 210 | constructor (private readonly channel: VideoChannel) { |
210 | super(channelKeysToKeep, 'channel', channel) | 211 | super(channelKeysToKeep, 'channel', channel) |
211 | } | 212 | } |
212 | } | 213 | } |
@@ -221,7 +222,7 @@ const videoAbuseKeysToKeep = [ | |||
221 | 'createdAt' | 222 | 'createdAt' |
222 | ] | 223 | ] |
223 | class VideoAbuseAuditView extends EntityAuditView { | 224 | class VideoAbuseAuditView extends EntityAuditView { |
224 | constructor (private videoAbuse: VideoAbuse) { | 225 | constructor (private readonly videoAbuse: VideoAbuse) { |
225 | super(videoAbuseKeysToKeep, 'abuse', videoAbuse) | 226 | super(videoAbuseKeysToKeep, 'abuse', videoAbuse) |
226 | } | 227 | } |
227 | } | 228 | } |
@@ -253,9 +254,12 @@ class CustomConfigAuditView extends EntityAuditView { | |||
253 | const infos: any = customConfig | 254 | const infos: any = customConfig |
254 | const resolutionsDict = infos.transcoding.resolutions | 255 | const resolutionsDict = infos.transcoding.resolutions |
255 | const resolutionsArray = [] | 256 | const resolutionsArray = [] |
256 | Object.entries(resolutionsDict).forEach(([resolution, isEnabled]) => { | 257 | |
257 | if (isEnabled) resolutionsArray.push(resolution) | 258 | Object.entries(resolutionsDict) |
258 | }) | 259 | .forEach(([ resolution, isEnabled ]) => { |
260 | if (isEnabled) resolutionsArray.push(resolution) | ||
261 | }) | ||
262 | |||
259 | Object.assign({}, infos, { transcoding: { resolutions: resolutionsArray } }) | 263 | Object.assign({}, infos, { transcoding: { resolutions: resolutionsArray } }) |
260 | super(customConfigKeysToKeep, 'config', infos) | 264 | super(customConfigKeysToKeep, 'config', infos) |
261 | } | 265 | } |
diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts index 7e8252aa4..2cecea450 100644 --- a/server/helpers/core-utils.ts +++ b/server/helpers/core-utils.ts | |||
@@ -1,9 +1,11 @@ | |||
1 | /* eslint-disable no-useless-call */ | ||
2 | |||
1 | /* | 3 | /* |
2 | Different from 'utils' because we don't not import other PeerTube modules. | 4 | Different from 'utils' because we don't not import other PeerTube modules. |
3 | Useful to avoid circular dependencies. | 5 | Useful to avoid circular dependencies. |
4 | */ | 6 | */ |
5 | 7 | ||
6 | import { createHash, HexBase64Latin1Encoding, pseudoRandomBytes } from 'crypto' | 8 | import { createHash, HexBase64Latin1Encoding, randomBytes } from 'crypto' |
7 | import { basename, isAbsolute, join, resolve } from 'path' | 9 | import { basename, isAbsolute, join, resolve } from 'path' |
8 | import * as pem from 'pem' | 10 | import * as pem from 'pem' |
9 | import { URL } from 'url' | 11 | import { URL } from 'url' |
@@ -22,31 +24,31 @@ const objectConverter = (oldObject: any, keyConverter: (e: string) => string, va | |||
22 | const newObject = {} | 24 | const newObject = {} |
23 | Object.keys(oldObject).forEach(oldKey => { | 25 | Object.keys(oldObject).forEach(oldKey => { |
24 | const newKey = keyConverter(oldKey) | 26 | const newKey = keyConverter(oldKey) |
25 | newObject[ newKey ] = objectConverter(oldObject[ oldKey ], keyConverter, valueConverter) | 27 | newObject[newKey] = objectConverter(oldObject[oldKey], keyConverter, valueConverter) |
26 | }) | 28 | }) |
27 | 29 | ||
28 | return newObject | 30 | return newObject |
29 | } | 31 | } |
30 | 32 | ||
31 | const timeTable = { | 33 | const timeTable = { |
32 | ms: 1, | 34 | ms: 1, |
33 | second: 1000, | 35 | second: 1000, |
34 | minute: 60000, | 36 | minute: 60000, |
35 | hour: 3600000, | 37 | hour: 3600000, |
36 | day: 3600000 * 24, | 38 | day: 3600000 * 24, |
37 | week: 3600000 * 24 * 7, | 39 | week: 3600000 * 24 * 7, |
38 | month: 3600000 * 24 * 30 | 40 | month: 3600000 * 24 * 30 |
39 | } | 41 | } |
40 | 42 | ||
41 | export function parseDurationToMs (duration: number | string): number { | 43 | export function parseDurationToMs (duration: number | string): number { |
42 | if (typeof duration === 'number') return duration | 44 | if (typeof duration === 'number') return duration |
43 | 45 | ||
44 | if (typeof duration === 'string') { | 46 | if (typeof duration === 'string') { |
45 | const split = duration.match(/^([\d\.,]+)\s?(\w+)$/) | 47 | const split = duration.match(/^([\d.,]+)\s?(\w+)$/) |
46 | 48 | ||
47 | if (split.length === 3) { | 49 | if (split.length === 3) { |
48 | const len = parseFloat(split[1]) | 50 | const len = parseFloat(split[1]) |
49 | let unit = split[2].replace(/s$/i,'').toLowerCase() | 51 | let unit = split[2].replace(/s$/i, '').toLowerCase() |
50 | if (unit === 'm') { | 52 | if (unit === 'm') { |
51 | unit = 'ms' | 53 | unit = 'ms' |
52 | } | 54 | } |
@@ -73,21 +75,21 @@ export function parseBytes (value: string | number): number { | |||
73 | 75 | ||
74 | if (value.match(tgm)) { | 76 | if (value.match(tgm)) { |
75 | match = value.match(tgm) | 77 | match = value.match(tgm) |
76 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 | 78 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 + |
77 | + parseInt(match[2], 10) * 1024 * 1024 * 1024 | 79 | parseInt(match[2], 10) * 1024 * 1024 * 1024 + |
78 | + parseInt(match[3], 10) * 1024 * 1024 | 80 | parseInt(match[3], 10) * 1024 * 1024 |
79 | } else if (value.match(tg)) { | 81 | } else if (value.match(tg)) { |
80 | match = value.match(tg) | 82 | match = value.match(tg) |
81 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 | 83 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 + |
82 | + parseInt(match[2], 10) * 1024 * 1024 * 1024 | 84 | parseInt(match[2], 10) * 1024 * 1024 * 1024 |
83 | } else if (value.match(tm)) { | 85 | } else if (value.match(tm)) { |
84 | match = value.match(tm) | 86 | match = value.match(tm) |
85 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 | 87 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 + |
86 | + parseInt(match[2], 10) * 1024 * 1024 | 88 | parseInt(match[2], 10) * 1024 * 1024 |
87 | } else if (value.match(gm)) { | 89 | } else if (value.match(gm)) { |
88 | match = value.match(gm) | 90 | match = value.match(gm) |
89 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 | 91 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 + |
90 | + parseInt(match[2], 10) * 1024 * 1024 | 92 | parseInt(match[2], 10) * 1024 * 1024 |
91 | } else if (value.match(t)) { | 93 | } else if (value.match(t)) { |
92 | match = value.match(t) | 94 | match = value.match(t) |
93 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 | 95 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 |
@@ -137,6 +139,7 @@ function getAppNumber () { | |||
137 | } | 139 | } |
138 | 140 | ||
139 | let rootPath: string | 141 | let rootPath: string |
142 | |||
140 | function root () { | 143 | function root () { |
141 | if (rootPath) return rootPath | 144 | if (rootPath) return rootPath |
142 | 145 | ||
@@ -163,7 +166,7 @@ function escapeHTML (stringParam) { | |||
163 | '=': '=' | 166 | '=': '=' |
164 | } | 167 | } |
165 | 168 | ||
166 | return String(stringParam).replace(/[&<>"'`=\/]/g, s => entityMap[s]) | 169 | return String(stringParam).replace(/[&<>"'`=/]/g, s => entityMap[s]) |
167 | } | 170 | } |
168 | 171 | ||
169 | function pageToStartAndCount (page: number, itemsPerPage: number) { | 172 | function pageToStartAndCount (page: number, itemsPerPage: number) { |
@@ -202,6 +205,7 @@ function sha1 (str: string | Buffer, encoding: HexBase64Latin1Encoding = 'hex') | |||
202 | function execShell (command: string, options?: ExecOptions) { | 205 | function execShell (command: string, options?: ExecOptions) { |
203 | return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => { | 206 | return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => { |
204 | exec(command, options, (err, stdout, stderr) => { | 207 | exec(command, options, (err, stdout, stderr) => { |
208 | // eslint-disable-next-line prefer-promise-reject-errors | ||
205 | if (err) return rej({ err, stdout, stderr }) | 209 | if (err) return rej({ err, stdout, stderr }) |
206 | 210 | ||
207 | return res({ stdout, stderr }) | 211 | return res({ stdout, stderr }) |
@@ -226,14 +230,6 @@ function promisify1<T, A> (func: (arg: T, cb: (err: any, result: A) => void) => | |||
226 | } | 230 | } |
227 | } | 231 | } |
228 | 232 | ||
229 | function promisify1WithVoid<T> (func: (arg: T, cb: (err: any) => void) => void): (arg: T) => Promise<void> { | ||
230 | return function promisified (arg: T): Promise<void> { | ||
231 | return new Promise<void>((resolve: () => void, reject: (err: any) => void) => { | ||
232 | func.apply(null, [ arg, (err: any) => err ? reject(err) : resolve() ]) | ||
233 | }) | ||
234 | } | ||
235 | } | ||
236 | |||
237 | function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) => void) => void): (arg1: T, arg2: U) => Promise<A> { | 233 | function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) => void) => void): (arg1: T, arg2: U) => Promise<A> { |
238 | return function promisified (arg1: T, arg2: U): Promise<A> { | 234 | return function promisified (arg1: T, arg2: U): Promise<A> { |
239 | return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { | 235 | return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { |
@@ -242,15 +238,7 @@ function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) | |||
242 | } | 238 | } |
243 | } | 239 | } |
244 | 240 | ||
245 | function promisify2WithVoid<T, U> (func: (arg1: T, arg2: U, cb: (err: any) => void) => void): (arg1: T, arg2: U) => Promise<void> { | 241 | const randomBytesPromise = promisify1<number, Buffer>(randomBytes) |
246 | return function promisified (arg1: T, arg2: U): Promise<void> { | ||
247 | return new Promise<void>((resolve: () => void, reject: (err: any) => void) => { | ||
248 | func.apply(null, [ arg1, arg2, (err: any) => err ? reject(err) : resolve() ]) | ||
249 | }) | ||
250 | } | ||
251 | } | ||
252 | |||
253 | const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes) | ||
254 | const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey) | 242 | const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey) |
255 | const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey) | 243 | const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey) |
256 | const execPromise2 = promisify2<string, any, string>(exec) | 244 | const execPromise2 = promisify2<string, any, string>(exec) |
@@ -280,7 +268,7 @@ export { | |||
280 | promisify1, | 268 | promisify1, |
281 | promisify2, | 269 | promisify2, |
282 | 270 | ||
283 | pseudoRandomBytesPromise, | 271 | randomBytesPromise, |
284 | createPrivateKey, | 272 | createPrivateKey, |
285 | getPublicKey, | 273 | getPublicKey, |
286 | execPromise2, | 274 | execPromise2, |
diff --git a/server/helpers/custom-jsonld-signature.ts b/server/helpers/custom-jsonld-signature.ts index a407a9fec..749c50cb3 100644 --- a/server/helpers/custom-jsonld-signature.ts +++ b/server/helpers/custom-jsonld-signature.ts | |||
@@ -5,52 +5,52 @@ import { logger } from './logger' | |||
5 | const CACHE = { | 5 | const CACHE = { |
6 | 'https://w3id.org/security/v1': { | 6 | 'https://w3id.org/security/v1': { |
7 | '@context': { | 7 | '@context': { |
8 | 'id': '@id', | 8 | id: '@id', |
9 | 'type': '@type', | 9 | type: '@type', |
10 | 10 | ||
11 | 'dc': 'http://purl.org/dc/terms/', | 11 | dc: 'http://purl.org/dc/terms/', |
12 | 'sec': 'https://w3id.org/security#', | 12 | sec: 'https://w3id.org/security#', |
13 | 'xsd': 'http://www.w3.org/2001/XMLSchema#', | 13 | xsd: 'http://www.w3.org/2001/XMLSchema#', |
14 | 14 | ||
15 | 'EcdsaKoblitzSignature2016': 'sec:EcdsaKoblitzSignature2016', | 15 | EcdsaKoblitzSignature2016: 'sec:EcdsaKoblitzSignature2016', |
16 | 'Ed25519Signature2018': 'sec:Ed25519Signature2018', | 16 | Ed25519Signature2018: 'sec:Ed25519Signature2018', |
17 | 'EncryptedMessage': 'sec:EncryptedMessage', | 17 | EncryptedMessage: 'sec:EncryptedMessage', |
18 | 'GraphSignature2012': 'sec:GraphSignature2012', | 18 | GraphSignature2012: 'sec:GraphSignature2012', |
19 | 'LinkedDataSignature2015': 'sec:LinkedDataSignature2015', | 19 | LinkedDataSignature2015: 'sec:LinkedDataSignature2015', |
20 | 'LinkedDataSignature2016': 'sec:LinkedDataSignature2016', | 20 | LinkedDataSignature2016: 'sec:LinkedDataSignature2016', |
21 | 'CryptographicKey': 'sec:Key', | 21 | CryptographicKey: 'sec:Key', |
22 | 22 | ||
23 | 'authenticationTag': 'sec:authenticationTag', | 23 | authenticationTag: 'sec:authenticationTag', |
24 | 'canonicalizationAlgorithm': 'sec:canonicalizationAlgorithm', | 24 | canonicalizationAlgorithm: 'sec:canonicalizationAlgorithm', |
25 | 'cipherAlgorithm': 'sec:cipherAlgorithm', | 25 | cipherAlgorithm: 'sec:cipherAlgorithm', |
26 | 'cipherData': 'sec:cipherData', | 26 | cipherData: 'sec:cipherData', |
27 | 'cipherKey': 'sec:cipherKey', | 27 | cipherKey: 'sec:cipherKey', |
28 | 'created': { '@id': 'dc:created', '@type': 'xsd:dateTime' }, | 28 | created: { '@id': 'dc:created', '@type': 'xsd:dateTime' }, |
29 | 'creator': { '@id': 'dc:creator', '@type': '@id' }, | 29 | creator: { '@id': 'dc:creator', '@type': '@id' }, |
30 | 'digestAlgorithm': 'sec:digestAlgorithm', | 30 | digestAlgorithm: 'sec:digestAlgorithm', |
31 | 'digestValue': 'sec:digestValue', | 31 | digestValue: 'sec:digestValue', |
32 | 'domain': 'sec:domain', | 32 | domain: 'sec:domain', |
33 | 'encryptionKey': 'sec:encryptionKey', | 33 | encryptionKey: 'sec:encryptionKey', |
34 | 'expiration': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, | 34 | expiration: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, |
35 | 'expires': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, | 35 | expires: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, |
36 | 'initializationVector': 'sec:initializationVector', | 36 | initializationVector: 'sec:initializationVector', |
37 | 'iterationCount': 'sec:iterationCount', | 37 | iterationCount: 'sec:iterationCount', |
38 | 'nonce': 'sec:nonce', | 38 | nonce: 'sec:nonce', |
39 | 'normalizationAlgorithm': 'sec:normalizationAlgorithm', | 39 | normalizationAlgorithm: 'sec:normalizationAlgorithm', |
40 | 'owner': { '@id': 'sec:owner', '@type': '@id' }, | 40 | owner: { '@id': 'sec:owner', '@type': '@id' }, |
41 | 'password': 'sec:password', | 41 | password: 'sec:password', |
42 | 'privateKey': { '@id': 'sec:privateKey', '@type': '@id' }, | 42 | privateKey: { '@id': 'sec:privateKey', '@type': '@id' }, |
43 | 'privateKeyPem': 'sec:privateKeyPem', | 43 | privateKeyPem: 'sec:privateKeyPem', |
44 | 'publicKey': { '@id': 'sec:publicKey', '@type': '@id' }, | 44 | publicKey: { '@id': 'sec:publicKey', '@type': '@id' }, |
45 | 'publicKeyBase58': 'sec:publicKeyBase58', | 45 | publicKeyBase58: 'sec:publicKeyBase58', |
46 | 'publicKeyPem': 'sec:publicKeyPem', | 46 | publicKeyPem: 'sec:publicKeyPem', |
47 | 'publicKeyWif': 'sec:publicKeyWif', | 47 | publicKeyWif: 'sec:publicKeyWif', |
48 | 'publicKeyService': { '@id': 'sec:publicKeyService', '@type': '@id' }, | 48 | publicKeyService: { '@id': 'sec:publicKeyService', '@type': '@id' }, |
49 | 'revoked': { '@id': 'sec:revoked', '@type': 'xsd:dateTime' }, | 49 | revoked: { '@id': 'sec:revoked', '@type': 'xsd:dateTime' }, |
50 | 'salt': 'sec:salt', | 50 | salt: 'sec:salt', |
51 | 'signature': 'sec:signature', | 51 | signature: 'sec:signature', |
52 | 'signatureAlgorithm': 'sec:signingAlgorithm', | 52 | signatureAlgorithm: 'sec:signingAlgorithm', |
53 | 'signatureValue': 'sec:signatureValue' | 53 | signatureValue: 'sec:signatureValue' |
54 | } | 54 | } |
55 | } | 55 | } |
56 | } | 56 | } |
@@ -60,12 +60,12 @@ const nodeDocumentLoader = jsonld.documentLoaders.node() | |||
60 | const lru = new AsyncLRU({ | 60 | const lru = new AsyncLRU({ |
61 | max: 10, | 61 | max: 10, |
62 | load: (url, cb) => { | 62 | load: (url, cb) => { |
63 | if (CACHE[ url ] !== undefined) { | 63 | if (CACHE[url] !== undefined) { |
64 | logger.debug('Using cache for JSON-LD %s.', url) | 64 | logger.debug('Using cache for JSON-LD %s.', url) |
65 | 65 | ||
66 | return cb(null, { | 66 | return cb(null, { |
67 | contextUrl: null, | 67 | contextUrl: null, |
68 | document: CACHE[ url ], | 68 | document: CACHE[url], |
69 | documentUrl: url | 69 | documentUrl: url |
70 | }) | 70 | }) |
71 | } | 71 | } |
diff --git a/server/helpers/custom-validators/activitypub/actor.ts b/server/helpers/custom-validators/activitypub/actor.ts index fa58e163f..fec67823d 100644 --- a/server/helpers/custom-validators/activitypub/actor.ts +++ b/server/helpers/custom-validators/activitypub/actor.ts | |||
@@ -6,7 +6,7 @@ import { isHostValid } from '../servers' | |||
6 | import { peertubeTruncate } from '@server/helpers/core-utils' | 6 | import { peertubeTruncate } from '@server/helpers/core-utils' |
7 | 7 | ||
8 | function isActorEndpointsObjectValid (endpointObject: any) { | 8 | function isActorEndpointsObjectValid (endpointObject: any) { |
9 | if (endpointObject && endpointObject.sharedInbox) { | 9 | if (endpointObject?.sharedInbox) { |
10 | return isActivityPubUrlValid(endpointObject.sharedInbox) | 10 | return isActivityPubUrlValid(endpointObject.sharedInbox) |
11 | } | 11 | } |
12 | 12 | ||
@@ -101,8 +101,6 @@ function normalizeActor (actor: any) { | |||
101 | actor.summary = null | 101 | actor.summary = null |
102 | } | 102 | } |
103 | } | 103 | } |
104 | |||
105 | return | ||
106 | } | 104 | } |
107 | 105 | ||
108 | function isValidActorHandle (handle: string) { | 106 | function isValidActorHandle (handle: string) { |
diff --git a/server/helpers/custom-validators/activitypub/cache-file.ts b/server/helpers/custom-validators/activitypub/cache-file.ts index 21d5c53ca..c5b3b4d9f 100644 --- a/server/helpers/custom-validators/activitypub/cache-file.ts +++ b/server/helpers/custom-validators/activitypub/cache-file.ts | |||
@@ -6,7 +6,7 @@ import { CacheFileObject } from '../../../../shared/models/activitypub/objects' | |||
6 | function isCacheFileObjectValid (object: CacheFileObject) { | 6 | function isCacheFileObjectValid (object: CacheFileObject) { |
7 | return exists(object) && | 7 | return exists(object) && |
8 | object.type === 'CacheFile' && | 8 | object.type === 'CacheFile' && |
9 | isDateValid(object.expires) && | 9 | (object.expires === null || isDateValid(object.expires)) && |
10 | isActivityPubUrlValid(object.object) && | 10 | isActivityPubUrlValid(object.object) && |
11 | (isRemoteVideoUrlValid(object.url) || isPlaylistRedundancyUrlValid(object.url)) | 11 | (isRemoteVideoUrlValid(object.url) || isPlaylistRedundancyUrlValid(object.url)) |
12 | } | 12 | } |
diff --git a/server/helpers/custom-validators/activitypub/video-comments.ts b/server/helpers/custom-validators/activitypub/video-comments.ts index aa3c246b5..ea852c491 100644 --- a/server/helpers/custom-validators/activitypub/video-comments.ts +++ b/server/helpers/custom-validators/activitypub/video-comments.ts | |||
@@ -48,8 +48,6 @@ function normalizeComment (comment: any) { | |||
48 | if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url | 48 | if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url |
49 | else comment.url = comment.id | 49 | else comment.url = comment.id |
50 | } | 50 | } |
51 | |||
52 | return | ||
53 | } | 51 | } |
54 | 52 | ||
55 | function isCommentTypeValid (comment: any): boolean { | 53 | function isCommentTypeValid (comment: any): boolean { |
diff --git a/server/helpers/custom-validators/activitypub/videos.ts b/server/helpers/custom-validators/activitypub/videos.ts index fe94bd58a..22b5e14a2 100644 --- a/server/helpers/custom-validators/activitypub/videos.ts +++ b/server/helpers/custom-validators/activitypub/videos.ts | |||
@@ -51,11 +51,16 @@ function sanitizeAndCheckVideoTorrentObject (video: any) { | |||
51 | logger.debug('Video has invalid captions', { video }) | 51 | logger.debug('Video has invalid captions', { video }) |
52 | return false | 52 | return false |
53 | } | 53 | } |
54 | if (!setValidRemoteIcon(video)) { | ||
55 | logger.debug('Video has invalid icons', { video }) | ||
56 | return false | ||
57 | } | ||
54 | 58 | ||
55 | // Default attributes | 59 | // Default attributes |
56 | if (!isVideoStateValid(video.state)) video.state = VideoState.PUBLISHED | 60 | if (!isVideoStateValid(video.state)) video.state = VideoState.PUBLISHED |
57 | if (!isBooleanValid(video.waitTranscoding)) video.waitTranscoding = false | 61 | if (!isBooleanValid(video.waitTranscoding)) video.waitTranscoding = false |
58 | if (!isBooleanValid(video.downloadEnabled)) video.downloadEnabled = true | 62 | if (!isBooleanValid(video.downloadEnabled)) video.downloadEnabled = true |
63 | if (!isBooleanValid(video.commentsEnabled)) video.commentsEnabled = false | ||
59 | 64 | ||
60 | return isActivityPubUrlValid(video.id) && | 65 | return isActivityPubUrlValid(video.id) && |
61 | isVideoNameValid(video.name) && | 66 | isVideoNameValid(video.name) && |
@@ -72,7 +77,6 @@ function sanitizeAndCheckVideoTorrentObject (video: any) { | |||
72 | isDateValid(video.updated) && | 77 | isDateValid(video.updated) && |
73 | (!video.originallyPublishedAt || isDateValid(video.originallyPublishedAt)) && | 78 | (!video.originallyPublishedAt || isDateValid(video.originallyPublishedAt)) && |
74 | (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) && | 79 | (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) && |
75 | isRemoteVideoIconValid(video.icon) && | ||
76 | video.url.length !== 0 && | 80 | video.url.length !== 0 && |
77 | video.attributedTo.length !== 0 | 81 | video.attributedTo.length !== 0 |
78 | } | 82 | } |
@@ -131,6 +135,8 @@ function setValidRemoteCaptions (video: any) { | |||
131 | if (Array.isArray(video.subtitleLanguage) === false) return false | 135 | if (Array.isArray(video.subtitleLanguage) === false) return false |
132 | 136 | ||
133 | video.subtitleLanguage = video.subtitleLanguage.filter(caption => { | 137 | video.subtitleLanguage = video.subtitleLanguage.filter(caption => { |
138 | if (!isActivityPubUrlValid(caption.url)) caption.url = null | ||
139 | |||
134 | return isRemoteStringIdentifierValid(caption) | 140 | return isRemoteStringIdentifierValid(caption) |
135 | }) | 141 | }) |
136 | 142 | ||
@@ -149,12 +155,19 @@ function isRemoteVideoContentValid (mediaType: string, content: string) { | |||
149 | return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content) | 155 | return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content) |
150 | } | 156 | } |
151 | 157 | ||
152 | function isRemoteVideoIconValid (icon: any) { | 158 | function setValidRemoteIcon (video: any) { |
153 | return icon.type === 'Image' && | 159 | if (video.icon && !isArray(video.icon)) video.icon = [ video.icon ] |
154 | isActivityPubUrlValid(icon.url) && | 160 | if (!video.icon) video.icon = [] |
155 | icon.mediaType === 'image/jpeg' && | 161 | |
156 | validator.isInt(icon.width + '', { min: 0 }) && | 162 | video.icon = video.icon.filter(icon => { |
157 | validator.isInt(icon.height + '', { min: 0 }) | 163 | return icon.type === 'Image' && |
164 | isActivityPubUrlValid(icon.url) && | ||
165 | icon.mediaType === 'image/jpeg' && | ||
166 | validator.isInt(icon.width + '', { min: 0 }) && | ||
167 | validator.isInt(icon.height + '', { min: 0 }) | ||
168 | }) | ||
169 | |||
170 | return video.icon.length !== 0 | ||
158 | } | 171 | } |
159 | 172 | ||
160 | function setValidRemoteVideoUrls (video: any) { | 173 | function setValidRemoteVideoUrls (video: any) { |
diff --git a/server/helpers/custom-validators/misc.ts b/server/helpers/custom-validators/misc.ts index 89149b3e0..cf32201c4 100644 --- a/server/helpers/custom-validators/misc.ts +++ b/server/helpers/custom-validators/misc.ts | |||
@@ -94,13 +94,13 @@ function isFileValid ( | |||
94 | if (isArray(files)) return optional | 94 | if (isArray(files)) return optional |
95 | 95 | ||
96 | // Should have a file | 96 | // Should have a file |
97 | const fileArray = files[ field ] | 97 | const fileArray = files[field] |
98 | if (!fileArray || fileArray.length === 0) { | 98 | if (!fileArray || fileArray.length === 0) { |
99 | return optional | 99 | return optional |
100 | } | 100 | } |
101 | 101 | ||
102 | // The file should exist | 102 | // The file should exist |
103 | const file = fileArray[ 0 ] | 103 | const file = fileArray[0] |
104 | if (!file || !file.originalname) return false | 104 | if (!file || !file.originalname) return false |
105 | 105 | ||
106 | // Check size | 106 | // Check size |
diff --git a/server/helpers/custom-validators/plugins.ts b/server/helpers/custom-validators/plugins.ts index 3af72547b..5a4531f72 100644 --- a/server/helpers/custom-validators/plugins.ts +++ b/server/helpers/custom-validators/plugins.ts | |||
@@ -14,7 +14,7 @@ function isPluginTypeValid (value: any) { | |||
14 | function isPluginNameValid (value: string) { | 14 | function isPluginNameValid (value: string) { |
15 | return exists(value) && | 15 | return exists(value) && |
16 | validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) && | 16 | validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) && |
17 | validator.matches(value, /^[a-z\-]+$/) | 17 | validator.matches(value, /^[a-z-]+$/) |
18 | } | 18 | } |
19 | 19 | ||
20 | function isNpmPluginNameValid (value: string) { | 20 | function isNpmPluginNameValid (value: string) { |
@@ -146,8 +146,8 @@ function isPackageJSONValid (packageJSON: PluginPackageJson, pluginType: PluginT | |||
146 | } | 146 | } |
147 | 147 | ||
148 | function isLibraryCodeValid (library: any) { | 148 | function isLibraryCodeValid (library: any) { |
149 | return typeof library.register === 'function' | 149 | return typeof library.register === 'function' && |
150 | && typeof library.unregister === 'function' | 150 | typeof library.unregister === 'function' |
151 | } | 151 | } |
152 | 152 | ||
153 | export { | 153 | export { |
diff --git a/server/helpers/custom-validators/user-notifications.ts b/server/helpers/custom-validators/user-notifications.ts index 5a4d10504..8a33b895b 100644 --- a/server/helpers/custom-validators/user-notifications.ts +++ b/server/helpers/custom-validators/user-notifications.ts | |||
@@ -9,7 +9,8 @@ function isUserNotificationTypeValid (value: any) { | |||
9 | 9 | ||
10 | function isUserNotificationSettingValid (value: any) { | 10 | function isUserNotificationSettingValid (value: any) { |
11 | return exists(value) && | 11 | return exists(value) && |
12 | validator.isInt('' + value) && ( | 12 | validator.isInt('' + value) && |
13 | ( | ||
13 | value === UserNotificationSettingValue.NONE || | 14 | value === UserNotificationSettingValue.NONE || |
14 | value === UserNotificationSettingValue.WEB || | 15 | value === UserNotificationSettingValue.WEB || |
15 | value === UserNotificationSettingValue.EMAIL || | 16 | value === UserNotificationSettingValue.EMAIL || |
diff --git a/server/helpers/custom-validators/video-abuses.ts b/server/helpers/custom-validators/video-abuses.ts index a9478c76a..5c7bc6fd9 100644 --- a/server/helpers/custom-validators/video-abuses.ts +++ b/server/helpers/custom-validators/video-abuses.ts | |||
@@ -1,8 +1,6 @@ | |||
1 | import { Response } from 'express' | ||
2 | import validator from 'validator' | 1 | import validator from 'validator' |
3 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' | 2 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' |
4 | import { exists } from './misc' | 3 | import { exists } from './misc' |
5 | import { VideoAbuseModel } from '../../models/video/video-abuse' | ||
6 | 4 | ||
7 | const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES | 5 | const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES |
8 | 6 | ||
@@ -15,7 +13,7 @@ function isVideoAbuseModerationCommentValid (value: string) { | |||
15 | } | 13 | } |
16 | 14 | ||
17 | function isVideoAbuseStateValid (value: string) { | 15 | function isVideoAbuseStateValid (value: string) { |
18 | return exists(value) && VIDEO_ABUSE_STATES[ value ] !== undefined | 16 | return exists(value) && VIDEO_ABUSE_STATES[value] !== undefined |
19 | } | 17 | } |
20 | 18 | ||
21 | // --------------------------------------------------------------------------- | 19 | // --------------------------------------------------------------------------- |
diff --git a/server/helpers/custom-validators/video-captions.ts b/server/helpers/custom-validators/video-captions.ts index d06eb3695..9abbce04a 100644 --- a/server/helpers/custom-validators/video-captions.ts +++ b/server/helpers/custom-validators/video-captions.ts | |||
@@ -2,7 +2,7 @@ import { CONSTRAINTS_FIELDS, MIMETYPES, VIDEO_LANGUAGES } from '../../initialize | |||
2 | import { exists, isFileValid } from './misc' | 2 | import { exists, isFileValid } from './misc' |
3 | 3 | ||
4 | function isVideoCaptionLanguageValid (value: any) { | 4 | function isVideoCaptionLanguageValid (value: any) { |
5 | return exists(value) && VIDEO_LANGUAGES[ value ] !== undefined | 5 | return exists(value) && VIDEO_LANGUAGES[value] !== undefined |
6 | } | 6 | } |
7 | 7 | ||
8 | const videoCaptionTypes = Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT) | 8 | const videoCaptionTypes = Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT) |
diff --git a/server/helpers/custom-validators/video-imports.ts b/server/helpers/custom-validators/video-imports.ts index ffad482b4..c571f5ddd 100644 --- a/server/helpers/custom-validators/video-imports.ts +++ b/server/helpers/custom-validators/video-imports.ts | |||
@@ -20,7 +20,7 @@ function isVideoImportTargetUrlValid (url: string) { | |||
20 | } | 20 | } |
21 | 21 | ||
22 | function isVideoImportStateValid (value: any) { | 22 | function isVideoImportStateValid (value: any) { |
23 | return exists(value) && VIDEO_IMPORT_STATES[ value ] !== undefined | 23 | return exists(value) && VIDEO_IMPORT_STATES[value] !== undefined |
24 | } | 24 | } |
25 | 25 | ||
26 | const videoTorrentImportTypes = Object.keys(MIMETYPES.TORRENT.MIMETYPE_EXT).map(m => `(${m})`) | 26 | const videoTorrentImportTypes = Object.keys(MIMETYPES.TORRENT.MIMETYPE_EXT).map(m => `(${m})`) |
diff --git a/server/helpers/custom-validators/video-playlists.ts b/server/helpers/custom-validators/video-playlists.ts index 4bb8384ab..180018fc5 100644 --- a/server/helpers/custom-validators/video-playlists.ts +++ b/server/helpers/custom-validators/video-playlists.ts | |||
@@ -1,8 +1,6 @@ | |||
1 | import { exists } from './misc' | 1 | import { exists } from './misc' |
2 | import validator from 'validator' | 2 | import validator from 'validator' |
3 | import { CONSTRAINTS_FIELDS, VIDEO_PLAYLIST_PRIVACIES, VIDEO_PLAYLIST_TYPES } from '../../initializers/constants' | 3 | import { CONSTRAINTS_FIELDS, VIDEO_PLAYLIST_PRIVACIES, VIDEO_PLAYLIST_TYPES } from '../../initializers/constants' |
4 | import * as express from 'express' | ||
5 | import { VideoPlaylistModel } from '../../models/video/video-playlist' | ||
6 | 4 | ||
7 | const PLAYLISTS_CONSTRAINT_FIELDS = CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS | 5 | const PLAYLISTS_CONSTRAINT_FIELDS = CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS |
8 | 6 | ||
@@ -15,7 +13,7 @@ function isVideoPlaylistDescriptionValid (value: any) { | |||
15 | } | 13 | } |
16 | 14 | ||
17 | function isVideoPlaylistPrivacyValid (value: number) { | 15 | function isVideoPlaylistPrivacyValid (value: number) { |
18 | return validator.isInt(value + '') && VIDEO_PLAYLIST_PRIVACIES[ value ] !== undefined | 16 | return validator.isInt(value + '') && VIDEO_PLAYLIST_PRIVACIES[value] !== undefined |
19 | } | 17 | } |
20 | 18 | ||
21 | function isVideoPlaylistTimestampValid (value: any) { | 19 | function isVideoPlaylistTimestampValid (value: any) { |
@@ -23,7 +21,7 @@ function isVideoPlaylistTimestampValid (value: any) { | |||
23 | } | 21 | } |
24 | 22 | ||
25 | function isVideoPlaylistTypeValid (value: any) { | 23 | function isVideoPlaylistTypeValid (value: any) { |
26 | return exists(value) && VIDEO_PLAYLIST_TYPES[ value ] !== undefined | 24 | return exists(value) && VIDEO_PLAYLIST_TYPES[value] !== undefined |
27 | } | 25 | } |
28 | 26 | ||
29 | // --------------------------------------------------------------------------- | 27 | // --------------------------------------------------------------------------- |
diff --git a/server/helpers/custom-validators/video-redundancies.ts b/server/helpers/custom-validators/video-redundancies.ts new file mode 100644 index 000000000..50a559c4f --- /dev/null +++ b/server/helpers/custom-validators/video-redundancies.ts | |||
@@ -0,0 +1,12 @@ | |||
1 | import { exists } from './misc' | ||
2 | |||
3 | function isVideoRedundancyTarget (value: any) { | ||
4 | return exists(value) && | ||
5 | (value === 'my-videos' || value === 'remote-videos') | ||
6 | } | ||
7 | |||
8 | // --------------------------------------------------------------------------- | ||
9 | |||
10 | export { | ||
11 | isVideoRedundancyTarget | ||
12 | } | ||
diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index a9e859e54..cfb430c63 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts | |||
@@ -20,15 +20,15 @@ function isVideoFilterValid (filter: VideoFilter) { | |||
20 | } | 20 | } |
21 | 21 | ||
22 | function isVideoCategoryValid (value: any) { | 22 | function isVideoCategoryValid (value: any) { |
23 | return value === null || VIDEO_CATEGORIES[ value ] !== undefined | 23 | return value === null || VIDEO_CATEGORIES[value] !== undefined |
24 | } | 24 | } |
25 | 25 | ||
26 | function isVideoStateValid (value: any) { | 26 | function isVideoStateValid (value: any) { |
27 | return exists(value) && VIDEO_STATES[ value ] !== undefined | 27 | return exists(value) && VIDEO_STATES[value] !== undefined |
28 | } | 28 | } |
29 | 29 | ||
30 | function isVideoLicenceValid (value: any) { | 30 | function isVideoLicenceValid (value: any) { |
31 | return value === null || VIDEO_LICENCES[ value ] !== undefined | 31 | return value === null || VIDEO_LICENCES[value] !== undefined |
32 | } | 32 | } |
33 | 33 | ||
34 | function isVideoLanguageValid (value: any) { | 34 | function isVideoLanguageValid (value: any) { |
@@ -98,7 +98,7 @@ function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | | |||
98 | } | 98 | } |
99 | 99 | ||
100 | function isVideoPrivacyValid (value: number) { | 100 | function isVideoPrivacyValid (value: number) { |
101 | return VIDEO_PRIVACIES[ value ] !== undefined | 101 | return VIDEO_PRIVACIES[value] !== undefined |
102 | } | 102 | } |
103 | 103 | ||
104 | function isScheduleVideoUpdatePrivacyValid (value: number) { | 104 | function isScheduleVideoUpdatePrivacyValid (value: number) { |
diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts index 9bf6d85a8..f46812977 100644 --- a/server/helpers/express-utils.ts +++ b/server/helpers/express-utils.ts | |||
@@ -12,7 +12,7 @@ function buildNSFWFilter (res?: express.Response, paramNSFW?: string) { | |||
12 | if (paramNSFW === 'false') return false | 12 | if (paramNSFW === 'false') return false |
13 | if (paramNSFW === 'both') return undefined | 13 | if (paramNSFW === 'both') return undefined |
14 | 14 | ||
15 | if (res && res.locals.oauth) { | 15 | if (res?.locals.oauth) { |
16 | const user = res.locals.oauth.token.User | 16 | const user = res.locals.oauth.token.User |
17 | 17 | ||
18 | // User does not want NSFW videos | 18 | // User does not want NSFW videos |
@@ -28,7 +28,7 @@ function buildNSFWFilter (res?: express.Response, paramNSFW?: string) { | |||
28 | return null | 28 | return null |
29 | } | 29 | } |
30 | 30 | ||
31 | function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[] }) { | 31 | function cleanUpReqFiles (req: { files: { [fieldname: string]: Express.Multer.File[] } | Express.Multer.File[] }) { |
32 | const files = req.files | 32 | const files = req.files |
33 | 33 | ||
34 | if (!files) return | 34 | if (!files) return |
@@ -39,7 +39,7 @@ function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer. | |||
39 | } | 39 | } |
40 | 40 | ||
41 | for (const key of Object.keys(files)) { | 41 | for (const key of Object.keys(files)) { |
42 | const file = files[ key ] | 42 | const file = files[key] |
43 | 43 | ||
44 | if (isArray(file)) file.forEach(f => deleteFileAsync(f.path)) | 44 | if (isArray(file)) file.forEach(f => deleteFileAsync(f.path)) |
45 | else deleteFileAsync(file.path) | 45 | else deleteFileAsync(file.path) |
@@ -65,18 +65,18 @@ function badRequest (req: express.Request, res: express.Response) { | |||
65 | 65 | ||
66 | function createReqFiles ( | 66 | function createReqFiles ( |
67 | fieldNames: string[], | 67 | fieldNames: string[], |
68 | mimeTypes: { [ id: string ]: string }, | 68 | mimeTypes: { [id: string]: string }, |
69 | destinations: { [ fieldName: string ]: string } | 69 | destinations: { [fieldName: string]: string } |
70 | ) { | 70 | ) { |
71 | const storage = multer.diskStorage({ | 71 | const storage = multer.diskStorage({ |
72 | destination: (req, file, cb) => { | 72 | destination: (req, file, cb) => { |
73 | cb(null, destinations[ file.fieldname ]) | 73 | cb(null, destinations[file.fieldname]) |
74 | }, | 74 | }, |
75 | 75 | ||
76 | filename: async (req, file, cb) => { | 76 | filename: async (req, file, cb) => { |
77 | let extension: string | 77 | let extension: string |
78 | const fileExtension = extname(file.originalname) | 78 | const fileExtension = extname(file.originalname) |
79 | const extensionFromMimetype = mimeTypes[ file.mimetype ] | 79 | const extensionFromMimetype = mimeTypes[file.mimetype] |
80 | 80 | ||
81 | // Take the file extension if we don't understand the mime type | 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 | 82 | // We have the OGG/OGV exception too because firefox sends a bad mime type when sending an OGG file |
@@ -99,7 +99,7 @@ function createReqFiles ( | |||
99 | } | 99 | } |
100 | }) | 100 | }) |
101 | 101 | ||
102 | let fields: { name: string, maxCount: number }[] = [] | 102 | const fields: { name: string, maxCount: number }[] = [] |
103 | for (const fieldName of fieldNames) { | 103 | for (const fieldName of fieldNames) { |
104 | fields.push({ | 104 | fields.push({ |
105 | name: fieldName, | 105 | name: fieldName, |
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index 00c32e99a..084516e55 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, getMaxBitrate, VideoResolution } from '../../shared/models/videos' | 3 | import { getMaxBitrate, getTargetBitrate, 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' |
@@ -8,6 +8,71 @@ import { checkFFmpegEncoders } from '../initializers/checker-before-init' | |||
8 | import { readFile, remove, writeFile } from 'fs-extra' | 8 | import { readFile, remove, writeFile } from 'fs-extra' |
9 | import { CONFIG } from '../initializers/config' | 9 | import { CONFIG } from '../initializers/config' |
10 | 10 | ||
11 | /** | ||
12 | * A toolbox to play with audio | ||
13 | */ | ||
14 | namespace audio { | ||
15 | export const get = (videoPath: string) => { | ||
16 | // without position, ffprobe considers the last input only | ||
17 | // we make it consider the first input only | ||
18 | // if you pass a file path to pos, then ffprobe acts on that file directly | ||
19 | return new Promise<{ absolutePath: string, audioStream?: any }>((res, rej) => { | ||
20 | |||
21 | function parseFfprobe (err: any, data: ffmpeg.FfprobeData) { | ||
22 | if (err) return rej(err) | ||
23 | |||
24 | if ('streams' in data) { | ||
25 | const audioStream = data.streams.find(stream => stream['codec_type'] === 'audio') | ||
26 | if (audioStream) { | ||
27 | return res({ | ||
28 | absolutePath: data.format.filename, | ||
29 | audioStream | ||
30 | }) | ||
31 | } | ||
32 | } | ||
33 | |||
34 | return res({ absolutePath: data.format.filename }) | ||
35 | } | ||
36 | |||
37 | return ffmpeg.ffprobe(videoPath, parseFfprobe) | ||
38 | }) | ||
39 | } | ||
40 | |||
41 | export namespace bitrate { | ||
42 | const baseKbitrate = 384 | ||
43 | |||
44 | const toBits = (kbits: number) => kbits * 8000 | ||
45 | |||
46 | export const aac = (bitrate: number): number => { | ||
47 | switch (true) { | ||
48 | case bitrate > toBits(baseKbitrate): | ||
49 | return baseKbitrate | ||
50 | |||
51 | default: | ||
52 | return -1 // we interpret it as a signal to copy the audio stream as is | ||
53 | } | ||
54 | } | ||
55 | |||
56 | export const mp3 = (bitrate: number): number => { | ||
57 | /* | ||
58 | a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac. | ||
59 | That's why, when using aac, we can go to lower kbit/sec. The equivalences | ||
60 | made here are not made to be accurate, especially with good mp3 encoders. | ||
61 | */ | ||
62 | switch (true) { | ||
63 | case bitrate <= toBits(192): | ||
64 | return 128 | ||
65 | |||
66 | case bitrate <= toBits(384): | ||
67 | return 256 | ||
68 | |||
69 | default: | ||
70 | return baseKbitrate | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | |||
11 | function computeResolutionsToTranscode (videoFileHeight: number) { | 76 | function computeResolutionsToTranscode (videoFileHeight: number) { |
12 | const resolutionsEnabled: number[] = [] | 77 | const resolutionsEnabled: number[] = [] |
13 | const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS | 78 | const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS |
@@ -24,7 +89,7 @@ function computeResolutionsToTranscode (videoFileHeight: number) { | |||
24 | ] | 89 | ] |
25 | 90 | ||
26 | for (const resolution of resolutions) { | 91 | for (const resolution of resolutions) { |
27 | if (configResolutions[ resolution + 'p' ] === true && videoFileHeight > resolution) { | 92 | if (configResolutions[resolution + 'p'] === true && videoFileHeight > resolution) { |
28 | resolutionsEnabled.push(resolution) | 93 | resolutionsEnabled.push(resolution) |
29 | } | 94 | } |
30 | } | 95 | } |
@@ -48,9 +113,9 @@ async function getVideoStreamCodec (path: string) { | |||
48 | const videoCodec = videoStream.codec_tag_string | 113 | const videoCodec = videoStream.codec_tag_string |
49 | 114 | ||
50 | const baseProfileMatrix = { | 115 | const baseProfileMatrix = { |
51 | 'High': '6400', | 116 | High: '6400', |
52 | 'Main': '4D40', | 117 | Main: '4D40', |
53 | 'Baseline': '42E0' | 118 | Baseline: '42E0' |
54 | } | 119 | } |
55 | 120 | ||
56 | let baseProfile = baseProfileMatrix[videoStream.profile] | 121 | let baseProfile = baseProfileMatrix[videoStream.profile] |
@@ -91,7 +156,7 @@ async function getVideoFileFPS (path: string) { | |||
91 | if (videoStream === null) return 0 | 156 | if (videoStream === null) return 0 |
92 | 157 | ||
93 | for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { | 158 | for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { |
94 | const valuesText: string = videoStream[ key ] | 159 | const valuesText: string = videoStream[key] |
95 | if (!valuesText) continue | 160 | if (!valuesText) continue |
96 | 161 | ||
97 | const [ frames, seconds ] = valuesText.split('/') | 162 | const [ frames, seconds ] = valuesText.split('/') |
@@ -191,7 +256,8 @@ interface OnlyAudioTranscodeOptions extends BaseTranscodeOptions { | |||
191 | type: 'only-audio' | 256 | type: 'only-audio' |
192 | } | 257 | } |
193 | 258 | ||
194 | type TranscodeOptions = HLSTranscodeOptions | 259 | type TranscodeOptions = |
260 | HLSTranscodeOptions | ||
195 | | VideoTranscodeOptions | 261 | | VideoTranscodeOptions |
196 | | MergeAudioTranscodeOptions | 262 | | MergeAudioTranscodeOptions |
197 | | OnlyAudioTranscodeOptions | 263 | | OnlyAudioTranscodeOptions |
@@ -204,13 +270,13 @@ function transcode (options: TranscodeOptions) { | |||
204 | .output(options.outputPath) | 270 | .output(options.outputPath) |
205 | 271 | ||
206 | if (options.type === 'quick-transcode') { | 272 | if (options.type === 'quick-transcode') { |
207 | command = await buildQuickTranscodeCommand(command) | 273 | command = buildQuickTranscodeCommand(command) |
208 | } else if (options.type === 'hls') { | 274 | } else if (options.type === 'hls') { |
209 | command = await buildHLSCommand(command, options) | 275 | command = await buildHLSCommand(command, options) |
210 | } else if (options.type === 'merge-audio') { | 276 | } else if (options.type === 'merge-audio') { |
211 | command = await buildAudioMergeCommand(command, options) | 277 | command = await buildAudioMergeCommand(command, options) |
212 | } else if (options.type === 'only-audio') { | 278 | } else if (options.type === 'only-audio') { |
213 | command = await buildOnlyAudioCommand(command, options) | 279 | command = buildOnlyAudioCommand(command, options) |
214 | } else { | 280 | } else { |
215 | command = await buildx264Command(command, options) | 281 | command = await buildx264Command(command, options) |
216 | } | 282 | } |
@@ -247,22 +313,27 @@ async function canDoQuickTranscode (path: string): Promise<boolean> { | |||
247 | 313 | ||
248 | // check video params | 314 | // check video params |
249 | if (videoStream == null) return false | 315 | if (videoStream == null) return false |
250 | if (videoStream[ 'codec_name' ] !== 'h264') return false | 316 | if (videoStream['codec_name'] !== 'h264') return false |
251 | if (videoStream[ 'pix_fmt' ] !== 'yuv420p') return false | 317 | if (videoStream['pix_fmt'] !== 'yuv420p') return false |
252 | if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false | 318 | if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false |
253 | if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false | 319 | if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false |
254 | 320 | ||
255 | // check audio params (if audio stream exists) | 321 | // check audio params (if audio stream exists) |
256 | if (parsedAudio.audioStream) { | 322 | if (parsedAudio.audioStream) { |
257 | if (parsedAudio.audioStream[ 'codec_name' ] !== 'aac') return false | 323 | if (parsedAudio.audioStream['codec_name'] !== 'aac') return false |
258 | 324 | ||
259 | const maxAudioBitrate = audio.bitrate[ 'aac' ](parsedAudio.audioStream[ 'bit_rate' ]) | 325 | const maxAudioBitrate = audio.bitrate['aac'](parsedAudio.audioStream['bit_rate']) |
260 | if (maxAudioBitrate !== -1 && parsedAudio.audioStream[ 'bit_rate' ] > maxAudioBitrate) return false | 326 | if (maxAudioBitrate !== -1 && parsedAudio.audioStream['bit_rate'] > maxAudioBitrate) return false |
261 | } | 327 | } |
262 | 328 | ||
263 | return true | 329 | return true |
264 | } | 330 | } |
265 | 331 | ||
332 | function getClosestFramerateStandard (fps: number, type: 'HD_STANDARD' | 'STANDARD'): number { | ||
333 | return VIDEO_TRANSCODING_FPS[type].slice(0) | ||
334 | .sort((a, b) => fps % a - fps % b)[0] | ||
335 | } | ||
336 | |||
266 | // --------------------------------------------------------------------------- | 337 | // --------------------------------------------------------------------------- |
267 | 338 | ||
268 | export { | 339 | export { |
@@ -286,13 +357,14 @@ export { | |||
286 | 357 | ||
287 | async function buildx264Command (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { | 358 | async function buildx264Command (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { |
288 | let fps = await getVideoFileFPS(options.inputPath) | 359 | let fps = await getVideoFileFPS(options.inputPath) |
289 | // On small/medium resolutions, limit FPS | ||
290 | if ( | 360 | if ( |
361 | // On small/medium resolutions, limit FPS | ||
291 | options.resolution !== undefined && | 362 | options.resolution !== undefined && |
292 | options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN && | 363 | options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN && |
293 | fps > VIDEO_TRANSCODING_FPS.AVERAGE | 364 | fps > VIDEO_TRANSCODING_FPS.AVERAGE |
294 | ) { | 365 | ) { |
295 | fps = VIDEO_TRANSCODING_FPS.AVERAGE | 366 | // Get closest standard framerate by modulo: downsampling has to be done to a divisor of the nominal fps value |
367 | fps = getClosestFramerateStandard(fps, 'STANDARD') | ||
296 | } | 368 | } |
297 | 369 | ||
298 | command = await presetH264(command, options.inputPath, options.resolution, fps) | 370 | command = await presetH264(command, options.inputPath, options.resolution, fps) |
@@ -305,7 +377,7 @@ async function buildx264Command (command: ffmpeg.FfmpegCommand, options: Transco | |||
305 | 377 | ||
306 | if (fps) { | 378 | if (fps) { |
307 | // Hard FPS limits | 379 | // Hard FPS limits |
308 | if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = VIDEO_TRANSCODING_FPS.MAX | 380 | if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = getClosestFramerateStandard(fps, 'HD_STANDARD') |
309 | else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN | 381 | else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN |
310 | 382 | ||
311 | command = command.withFPS(fps) | 383 | command = command.withFPS(fps) |
@@ -327,14 +399,14 @@ async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: M | |||
327 | return command | 399 | return command |
328 | } | 400 | } |
329 | 401 | ||
330 | async function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) { | 402 | function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) { |
331 | command = await presetOnlyAudio(command) | 403 | command = presetOnlyAudio(command) |
332 | 404 | ||
333 | return command | 405 | return command |
334 | } | 406 | } |
335 | 407 | ||
336 | async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) { | 408 | function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) { |
337 | command = await presetCopy(command) | 409 | command = presetCopy(command) |
338 | 410 | ||
339 | command = command.outputOption('-map_metadata -1') // strip all metadata | 411 | command = command.outputOption('-map_metadata -1') // strip all metadata |
340 | .outputOption('-movflags faststart') | 412 | .outputOption('-movflags faststart') |
@@ -345,7 +417,7 @@ async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) { | |||
345 | async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) { | 417 | async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) { |
346 | const videoPath = getHLSVideoPath(options) | 418 | const videoPath = getHLSVideoPath(options) |
347 | 419 | ||
348 | if (options.copyCodecs) command = await presetCopy(command) | 420 | if (options.copyCodecs) command = presetCopy(command) |
349 | else command = await buildx264Command(command, options) | 421 | else command = await buildx264Command(command, options) |
350 | 422 | ||
351 | command = command.outputOption('-hls_time 4') | 423 | command = command.outputOption('-hls_time 4') |
@@ -413,71 +485,6 @@ async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, input: string, | |||
413 | } | 485 | } |
414 | 486 | ||
415 | /** | 487 | /** |
416 | * A toolbox to play with audio | ||
417 | */ | ||
418 | namespace audio { | ||
419 | export const get = (videoPath: string) => { | ||
420 | // without position, ffprobe considers the last input only | ||
421 | // we make it consider the first input only | ||
422 | // if you pass a file path to pos, then ffprobe acts on that file directly | ||
423 | return new Promise<{ absolutePath: string, audioStream?: any }>((res, rej) => { | ||
424 | |||
425 | function parseFfprobe (err: any, data: ffmpeg.FfprobeData) { | ||
426 | if (err) return rej(err) | ||
427 | |||
428 | if ('streams' in data) { | ||
429 | const audioStream = data.streams.find(stream => stream[ 'codec_type' ] === 'audio') | ||
430 | if (audioStream) { | ||
431 | return res({ | ||
432 | absolutePath: data.format.filename, | ||
433 | audioStream | ||
434 | }) | ||
435 | } | ||
436 | } | ||
437 | |||
438 | return res({ absolutePath: data.format.filename }) | ||
439 | } | ||
440 | |||
441 | return ffmpeg.ffprobe(videoPath, parseFfprobe) | ||
442 | }) | ||
443 | } | ||
444 | |||
445 | export namespace bitrate { | ||
446 | const baseKbitrate = 384 | ||
447 | |||
448 | const toBits = (kbits: number) => kbits * 8000 | ||
449 | |||
450 | export const aac = (bitrate: number): number => { | ||
451 | switch (true) { | ||
452 | case bitrate > toBits(baseKbitrate): | ||
453 | return baseKbitrate | ||
454 | |||
455 | default: | ||
456 | return -1 // we interpret it as a signal to copy the audio stream as is | ||
457 | } | ||
458 | } | ||
459 | |||
460 | export const mp3 = (bitrate: number): number => { | ||
461 | /* | ||
462 | a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac. | ||
463 | That's why, when using aac, we can go to lower kbit/sec. The equivalences | ||
464 | made here are not made to be accurate, especially with good mp3 encoders. | ||
465 | */ | ||
466 | switch (true) { | ||
467 | case bitrate <= toBits(192): | ||
468 | return 128 | ||
469 | |||
470 | case bitrate <= toBits(384): | ||
471 | return 256 | ||
472 | |||
473 | default: | ||
474 | return baseKbitrate | ||
475 | } | ||
476 | } | ||
477 | } | ||
478 | } | ||
479 | |||
480 | /** | ||
481 | * Standard profile, with variable bitrate audio and faststart. | 488 | * Standard profile, with variable bitrate audio and faststart. |
482 | * | 489 | * |
483 | * As for the audio, quality '5' is the highest and ensures 96-112kbps/channel | 490 | * As for the audio, quality '5' is the highest and ensures 96-112kbps/channel |
@@ -507,10 +514,10 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolut | |||
507 | // of course this is far from perfect, but it might save some space in the end | 514 | // of course this is far from perfect, but it might save some space in the end |
508 | localCommand = localCommand.audioCodec('aac') | 515 | localCommand = localCommand.audioCodec('aac') |
509 | 516 | ||
510 | const audioCodecName = parsedAudio.audioStream[ 'codec_name' ] | 517 | const audioCodecName = parsedAudio.audioStream['codec_name'] |
511 | 518 | ||
512 | if (audio.bitrate[ audioCodecName ]) { | 519 | if (audio.bitrate[audioCodecName]) { |
513 | const bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ]) | 520 | const bitrate = audio.bitrate[audioCodecName](parsedAudio.audioStream['bit_rate']) |
514 | if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate) | 521 | if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate) |
515 | } | 522 | } |
516 | } | 523 | } |
@@ -531,14 +538,14 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolut | |||
531 | return localCommand | 538 | return localCommand |
532 | } | 539 | } |
533 | 540 | ||
534 | async function presetCopy (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> { | 541 | function presetCopy (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand { |
535 | return command | 542 | return command |
536 | .format('mp4') | 543 | .format('mp4') |
537 | .videoCodec('copy') | 544 | .videoCodec('copy') |
538 | .audioCodec('copy') | 545 | .audioCodec('copy') |
539 | } | 546 | } |
540 | 547 | ||
541 | async function presetOnlyAudio (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> { | 548 | function presetOnlyAudio (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand { |
542 | return command | 549 | return command |
543 | .format('mp4') | 550 | .format('mp4') |
544 | .audioCodec('copy') | 551 | .audioCodec('copy') |
diff --git a/server/helpers/logger.ts b/server/helpers/logger.ts index 395417612..b8ae28b3f 100644 --- a/server/helpers/logger.ts +++ b/server/helpers/logger.ts | |||
@@ -5,7 +5,7 @@ import * as winston from 'winston' | |||
5 | import { FileTransportOptions } from 'winston/lib/winston/transports' | 5 | import { FileTransportOptions } from 'winston/lib/winston/transports' |
6 | import { CONFIG } from '../initializers/config' | 6 | import { CONFIG } from '../initializers/config' |
7 | import { omit } from 'lodash' | 7 | import { omit } from 'lodash' |
8 | import { LOG_FILENAME } from '@server/initializers/constants' | 8 | import { LOG_FILENAME } from '../initializers/constants' |
9 | 9 | ||
10 | const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT | 10 | const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT |
11 | 11 | ||
@@ -27,7 +27,7 @@ function getLoggerReplacer () { | |||
27 | if (value instanceof Error) { | 27 | if (value instanceof Error) { |
28 | const error = {} | 28 | const error = {} |
29 | 29 | ||
30 | Object.getOwnPropertyNames(value).forEach(key => error[ key ] = value[ key ]) | 30 | Object.getOwnPropertyNames(value).forEach(key => { error[key] = value[key] }) |
31 | 31 | ||
32 | return error | 32 | return error |
33 | } | 33 | } |
@@ -98,19 +98,20 @@ function bunyanLogFactory (level: string) { | |||
98 | let args: any[] = [] | 98 | let args: any[] = [] |
99 | args.concat(arguments) | 99 | args.concat(arguments) |
100 | 100 | ||
101 | if (arguments[ 0 ] instanceof Error) { | 101 | if (arguments[0] instanceof Error) { |
102 | meta = arguments[ 0 ].toString() | 102 | meta = arguments[0].toString() |
103 | args = Array.prototype.slice.call(arguments, 1) | 103 | args = Array.prototype.slice.call(arguments, 1) |
104 | args.push(meta) | 104 | args.push(meta) |
105 | } else if (typeof (args[ 0 ]) !== 'string') { | 105 | } else if (typeof (args[0]) !== 'string') { |
106 | meta = arguments[ 0 ] | 106 | meta = arguments[0] |
107 | args = Array.prototype.slice.call(arguments, 1) | 107 | args = Array.prototype.slice.call(arguments, 1) |
108 | args.push(meta) | 108 | args.push(meta) |
109 | } | 109 | } |
110 | 110 | ||
111 | logger[ level ].apply(logger, args) | 111 | logger[level].apply(logger, args) |
112 | } | 112 | } |
113 | } | 113 | } |
114 | |||
114 | const bunyanLogger = { | 115 | const bunyanLogger = { |
115 | trace: bunyanLogFactory('debug'), | 116 | trace: bunyanLogFactory('debug'), |
116 | debug: bunyanLogFactory('debug'), | 117 | debug: bunyanLogFactory('debug'), |
diff --git a/server/helpers/regexp.ts b/server/helpers/regexp.ts index 2336654b0..cfc2be488 100644 --- a/server/helpers/regexp.ts +++ b/server/helpers/regexp.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | // Thanks to https://regex101.com | 1 | // Thanks to https://regex101.com |
2 | function regexpCapture (str: string, regex: RegExp, maxIterations = 100) { | 2 | function regexpCapture (str: string, regex: RegExp, maxIterations = 100) { |
3 | const result: RegExpExecArray[] = [] | ||
3 | let m: RegExpExecArray | 4 | let m: RegExpExecArray |
4 | let i = 0 | 5 | let i = 0 |
5 | let result: RegExpExecArray[] = [] | ||
6 | 6 | ||
7 | // tslint:disable:no-conditional-assignment | 7 | // tslint:disable:no-conditional-assignment |
8 | while ((m = regex.exec(str)) !== null && i < maxIterations) { | 8 | while ((m = regex.exec(str)) !== null && i < maxIterations) { |
diff --git a/server/helpers/register-ts-paths.ts b/server/helpers/register-ts-paths.ts index e8db369e3..eec7fed3e 100644 --- a/server/helpers/register-ts-paths.ts +++ b/server/helpers/register-ts-paths.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { resolve } from 'path' | 1 | import { resolve } from 'path' |
2 | const tsConfigPaths = require('tsconfig-paths') | 2 | import tsConfigPaths = require('tsconfig-paths') |
3 | 3 | ||
4 | const tsConfig = require('../../tsconfig.json') | 4 | const tsConfig = require('../../tsconfig.json') |
5 | 5 | ||
diff --git a/server/helpers/signup.ts b/server/helpers/signup.ts index 7c73f7c5c..d34ff2db5 100644 --- a/server/helpers/signup.ts +++ b/server/helpers/signup.ts | |||
@@ -21,7 +21,7 @@ async function isSignupAllowed (): Promise<{ allowed: boolean, errorMessage?: st | |||
21 | 21 | ||
22 | function isSignupAllowedForCurrentIP (ip: string) { | 22 | function isSignupAllowedForCurrentIP (ip: string) { |
23 | const addr = ipaddr.parse(ip) | 23 | const addr = ipaddr.parse(ip) |
24 | let excludeList = [ 'blacklist' ] | 24 | const excludeList = [ 'blacklist' ] |
25 | let matched = '' | 25 | let matched = '' |
26 | 26 | ||
27 | // if there is a valid, non-empty whitelist, we exclude all unknown adresses too | 27 | // if there is a valid, non-empty whitelist, we exclude all unknown adresses too |
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts index 4c6f200f8..7a4c781cc 100644 --- a/server/helpers/utils.ts +++ b/server/helpers/utils.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { ResultList } from '../../shared' | 1 | import { ResultList } from '../../shared' |
2 | import { ApplicationModel } from '../models/application/application' | 2 | import { ApplicationModel } from '../models/application/application' |
3 | import { execPromise, execPromise2, pseudoRandomBytesPromise, sha256 } from './core-utils' | 3 | import { execPromise, execPromise2, randomBytesPromise, sha256 } from './core-utils' |
4 | import { logger } from './logger' | 4 | import { logger } from './logger' |
5 | import { join } from 'path' | 5 | import { join } from 'path' |
6 | import { Instance as ParseTorrent } from 'parse-torrent' | 6 | import { Instance as ParseTorrent } from 'parse-torrent' |
@@ -14,7 +14,7 @@ function deleteFileAsync (path: string) { | |||
14 | } | 14 | } |
15 | 15 | ||
16 | async function generateRandomString (size: number) { | 16 | async function generateRandomString (size: number) { |
17 | const raw = await pseudoRandomBytesPromise(size) | 17 | const raw = await randomBytesPromise(size) |
18 | 18 | ||
19 | return raw.toString('hex') | 19 | return raw.toString('hex') |
20 | } | 20 | } |
diff --git a/server/helpers/webtorrent.ts b/server/helpers/webtorrent.ts index 3a99518c6..b25e44fcd 100644 --- a/server/helpers/webtorrent.ts +++ b/server/helpers/webtorrent.ts | |||
@@ -9,12 +9,12 @@ import { promisify2 } from './core-utils' | |||
9 | import { MVideo } from '@server/typings/models/video/video' | 9 | import { MVideo } from '@server/typings/models/video/video' |
10 | import { MVideoFile, MVideoFileRedundanciesOpt } from '@server/typings/models/video/video-file' | 10 | import { MVideoFile, MVideoFileRedundanciesOpt } from '@server/typings/models/video/video-file' |
11 | import { isStreamingPlaylist, MStreamingPlaylistVideo } from '@server/typings/models/video/video-streaming-playlist' | 11 | import { isStreamingPlaylist, MStreamingPlaylistVideo } from '@server/typings/models/video/video-streaming-playlist' |
12 | import { STATIC_PATHS, WEBSERVER } from '@server/initializers/constants' | 12 | import { WEBSERVER } from '@server/initializers/constants' |
13 | import * as parseTorrent from 'parse-torrent' | 13 | import * as parseTorrent from 'parse-torrent' |
14 | import * as magnetUtil from 'magnet-uri' | 14 | import * as magnetUtil from 'magnet-uri' |
15 | import { isArray } from '@server/helpers/custom-validators/misc' | 15 | import { isArray } from '@server/helpers/custom-validators/misc' |
16 | import { extractVideo } from '@server/lib/videos' | 16 | import { extractVideo } from '@server/lib/videos' |
17 | import { getTorrentFileName, getVideoFilename, getVideoFilePath } from '@server/lib/video-paths' | 17 | import { getTorrentFileName, getVideoFilePath } from '@server/lib/video-paths' |
18 | 18 | ||
19 | const createTorrentPromise = promisify2<string, any, any>(createTorrent) | 19 | const createTorrentPromise = promisify2<string, any, any>(createTorrent) |
20 | 20 | ||
@@ -39,7 +39,7 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName | |||
39 | if (torrent.files.length !== 1) { | 39 | if (torrent.files.length !== 1) { |
40 | if (timer) clearTimeout(timer) | 40 | if (timer) clearTimeout(timer) |
41 | 41 | ||
42 | for (let file of torrent.files) { | 42 | for (const file of torrent.files) { |
43 | deleteDownloadedFile({ directoryPath, filepath: file.path }) | 43 | deleteDownloadedFile({ directoryPath, filepath: file.path }) |
44 | } | 44 | } |
45 | 45 | ||
@@ -47,15 +47,16 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName | |||
47 | .then(() => rej(new Error('Cannot import torrent ' + torrentId + ': there are multiple files in it'))) | 47 | .then(() => rej(new Error('Cannot import torrent ' + torrentId + ': there are multiple files in it'))) |
48 | } | 48 | } |
49 | 49 | ||
50 | file = torrent.files[ 0 ] | 50 | file = torrent.files[0] |
51 | 51 | ||
52 | // FIXME: avoid creating another stream when https://github.com/webtorrent/webtorrent/issues/1517 is fixed | 52 | // FIXME: avoid creating another stream when https://github.com/webtorrent/webtorrent/issues/1517 is fixed |
53 | const writeStream = createWriteStream(path) | 53 | const writeStream = createWriteStream(path) |
54 | writeStream.on('finish', () => { | 54 | writeStream.on('finish', () => { |
55 | if (timer) clearTimeout(timer) | 55 | if (timer) clearTimeout(timer) |
56 | 56 | ||
57 | return safeWebtorrentDestroy(webtorrent, torrentId, { directoryPath, filepath: file.path }, target.torrentName) | 57 | safeWebtorrentDestroy(webtorrent, torrentId, { directoryPath, filepath: file.path }, target.torrentName) |
58 | .then(() => res(path)) | 58 | .then(() => res(path)) |
59 | .catch(err => logger.error('Cannot destroy webtorrent.', { err })) | ||
59 | }) | 60 | }) |
60 | 61 | ||
61 | file.createReadStream().pipe(writeStream) | 62 | file.createReadStream().pipe(writeStream) |
@@ -63,9 +64,16 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName | |||
63 | 64 | ||
64 | torrent.on('error', err => rej(err)) | 65 | torrent.on('error', err => rej(err)) |
65 | 66 | ||
66 | timer = setTimeout(async () => { | 67 | timer = setTimeout(() => { |
67 | return safeWebtorrentDestroy(webtorrent, torrentId, file ? { directoryPath, filepath: file.path } : undefined, target.torrentName) | 68 | const err = new Error('Webtorrent download timeout.') |
68 | .then(() => rej(new Error('Webtorrent download timeout.'))) | 69 | |
70 | safeWebtorrentDestroy(webtorrent, torrentId, file ? { directoryPath, filepath: file.path } : undefined, target.torrentName) | ||
71 | .then(() => rej(err)) | ||
72 | .catch(destroyErr => { | ||
73 | logger.error('Cannot destroy webtorrent.', { err: destroyErr }) | ||
74 | rej(err) | ||
75 | }) | ||
76 | |||
69 | }, timeout) | 77 | }, timeout) |
70 | }) | 78 | }) |
71 | } | 79 | } |
diff --git a/server/helpers/youtube-dl.ts b/server/helpers/youtube-dl.ts index 577a59dbf..fc9d416a1 100644 --- a/server/helpers/youtube-dl.ts +++ b/server/helpers/youtube-dl.ts | |||
@@ -24,20 +24,23 @@ const processOptions = { | |||
24 | } | 24 | } |
25 | 25 | ||
26 | function getYoutubeDLInfo (url: string, opts?: string[]): Promise<YoutubeDLInfo> { | 26 | function getYoutubeDLInfo (url: string, opts?: string[]): Promise<YoutubeDLInfo> { |
27 | return new Promise<YoutubeDLInfo>(async (res, rej) => { | 27 | return new Promise<YoutubeDLInfo>((res, rej) => { |
28 | let args = opts || [ '-j', '--flat-playlist' ] | 28 | let args = opts || [ '-j', '--flat-playlist' ] |
29 | args = wrapWithProxyOptions(args) | 29 | args = wrapWithProxyOptions(args) |
30 | 30 | ||
31 | const youtubeDL = await safeGetYoutubeDL() | 31 | safeGetYoutubeDL() |
32 | youtubeDL.getInfo(url, args, processOptions, (err, info) => { | 32 | .then(youtubeDL => { |
33 | if (err) return rej(err) | 33 | youtubeDL.getInfo(url, args, processOptions, (err, info) => { |
34 | if (info.is_live === true) return rej(new Error('Cannot download a live streaming.')) | 34 | if (err) return rej(err) |
35 | if (info.is_live === true) return rej(new Error('Cannot download a live streaming.')) | ||
35 | 36 | ||
36 | const obj = buildVideoInfo(normalizeObject(info)) | 37 | const obj = buildVideoInfo(normalizeObject(info)) |
37 | if (obj.name && obj.name.length < CONSTRAINTS_FIELDS.VIDEOS.NAME.min) obj.name += ' video' | 38 | if (obj.name && obj.name.length < CONSTRAINTS_FIELDS.VIDEOS.NAME.min) obj.name += ' video' |
38 | 39 | ||
39 | return res(obj) | 40 | return res(obj) |
40 | }) | 41 | }) |
42 | }) | ||
43 | .catch(err => rej(err)) | ||
41 | }) | 44 | }) |
42 | } | 45 | } |
43 | 46 | ||
@@ -54,26 +57,34 @@ function downloadYoutubeDLVideo (url: string, timeout: number) { | |||
54 | options = options.concat([ '--ffmpeg-location', process.env.FFMPEG_PATH ]) | 57 | options = options.concat([ '--ffmpeg-location', process.env.FFMPEG_PATH ]) |
55 | } | 58 | } |
56 | 59 | ||
57 | return new Promise<string>(async (res, rej) => { | 60 | return new Promise<string>((res, rej) => { |
58 | const youtubeDL = await safeGetYoutubeDL() | 61 | safeGetYoutubeDL() |
59 | youtubeDL.exec(url, options, processOptions, err => { | 62 | .then(youtubeDL => { |
60 | clearTimeout(timer) | 63 | youtubeDL.exec(url, options, processOptions, err => { |
64 | clearTimeout(timer) | ||
61 | 65 | ||
62 | if (err) { | 66 | if (err) { |
63 | remove(path) | 67 | remove(path) |
64 | .catch(err => logger.error('Cannot delete path on YoutubeDL error.', { err })) | 68 | .catch(err => logger.error('Cannot delete path on YoutubeDL error.', { err })) |
65 | 69 | ||
66 | return rej(err) | 70 | return rej(err) |
67 | } | 71 | } |
68 | 72 | ||
69 | return res(path) | 73 | return res(path) |
70 | }) | 74 | }) |
71 | 75 | ||
72 | timer = setTimeout(async () => { | 76 | timer = setTimeout(() => { |
73 | await remove(path) | 77 | const err = new Error('YoutubeDL download timeout.') |
74 | 78 | ||
75 | return rej(new Error('YoutubeDL download timeout.')) | 79 | remove(path) |
76 | }, timeout) | 80 | .finally(() => rej(err)) |
81 | .catch(err => { | ||
82 | logger.error('Cannot remove %s in youtubeDL timeout.', path, { err }) | ||
83 | return rej(err) | ||
84 | }) | ||
85 | }, timeout) | ||
86 | }) | ||
87 | .catch(err => rej(err)) | ||
77 | }) | 88 | }) |
78 | } | 89 | } |
79 | 90 | ||
@@ -103,7 +114,7 @@ async function updateYoutubeDLBinary () { | |||
103 | 114 | ||
104 | const url = result.headers.location | 115 | const url = result.headers.location |
105 | const downloadFile = request.get(url) | 116 | const downloadFile = request.get(url) |
106 | const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[ 1 ] | 117 | const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[1] |
107 | 118 | ||
108 | downloadFile.on('response', result => { | 119 | downloadFile.on('response', result => { |
109 | if (result.statusCode !== 200) { | 120 | if (result.statusCode !== 200) { |
diff --git a/server/initializers/checker-after-init.ts b/server/initializers/checker-after-init.ts index 44efd346c..978023129 100644 --- a/server/initializers/checker-after-init.ts +++ b/server/initializers/checker-after-init.ts | |||
@@ -3,7 +3,7 @@ import { isProdInstance, isTestInstance } from '../helpers/core-utils' | |||
3 | import { UserModel } from '../models/account/user' | 3 | import { UserModel } from '../models/account/user' |
4 | import { ApplicationModel } from '../models/application/application' | 4 | import { ApplicationModel } from '../models/application/application' |
5 | import { OAuthClientModel } from '../models/oauth/oauth-client' | 5 | import { OAuthClientModel } from '../models/oauth/oauth-client' |
6 | import { parse } from 'url' | 6 | import { URL } from 'url' |
7 | import { CONFIG } from './config' | 7 | import { CONFIG } from './config' |
8 | import { logger } from '../helpers/logger' | 8 | import { logger } from '../helpers/logger' |
9 | import { getServerActor } from '../helpers/utils' | 9 | import { getServerActor } from '../helpers/utils' |
@@ -16,7 +16,7 @@ import { WEBSERVER } from './constants' | |||
16 | async function checkActivityPubUrls () { | 16 | async function checkActivityPubUrls () { |
17 | const actor = await getServerActor() | 17 | const actor = await getServerActor() |
18 | 18 | ||
19 | const parsed = parse(actor.url) | 19 | const parsed = new URL(actor.url) |
20 | if (WEBSERVER.HOST !== parsed.host) { | 20 | if (WEBSERVER.HOST !== parsed.host) { |
21 | const NODE_ENV = config.util.getEnv('NODE_ENV') | 21 | const NODE_ENV = config.util.getEnv('NODE_ENV') |
22 | const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR') | 22 | const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR') |
diff --git a/server/initializers/checker-before-init.ts b/server/initializers/checker-before-init.ts index 9731a0af9..a75f2cec2 100644 --- a/server/initializers/checker-before-init.ts +++ b/server/initializers/checker-before-init.ts | |||
@@ -35,8 +35,8 @@ function checkMissedConfig () { | |||
35 | ] | 35 | ] |
36 | const requiredAlternatives = [ | 36 | const requiredAlternatives = [ |
37 | [ // set | 37 | [ // set |
38 | ['redis.hostname', 'redis.port'], // alternative | 38 | [ 'redis.hostname', 'redis.port' ], // alternative |
39 | ['redis.socket'] | 39 | [ 'redis.socket' ] |
40 | ] | 40 | ] |
41 | ] | 41 | ] |
42 | const miss: string[] = [] | 42 | const miss: string[] = [] |
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index 7fd77f3e8..75372fa4e 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { IConfig } from 'config' | 1 | import { IConfig } from 'config' |
2 | import { dirname, join } from 'path' | 2 | import { dirname, join } from 'path' |
3 | import { VideosRedundancy } from '../../shared/models' | 3 | import { VideosRedundancyStrategy } from '../../shared/models' |
4 | // Do not use barrels, remain constants as independent as possible | 4 | // Do not use barrels, remain constants as independent as possible |
5 | import { buildPath, parseBytes, parseDurationToMs, root } from '../helpers/core-utils' | 5 | import { buildPath, parseBytes, parseDurationToMs, root } from '../helpers/core-utils' |
6 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' | 6 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' |
@@ -301,10 +301,10 @@ function getLocalConfigFilePath () { | |||
301 | if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}` | 301 | if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}` |
302 | if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}` | 302 | if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}` |
303 | 303 | ||
304 | return join(dirname(configSources[ 0 ].name), filename + '.json') | 304 | return join(dirname(configSources[0].name), filename + '.json') |
305 | } | 305 | } |
306 | 306 | ||
307 | function buildVideosRedundancy (objs: any[]): VideosRedundancy[] { | 307 | function buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] { |
308 | if (!objs) return [] | 308 | if (!objs) return [] |
309 | 309 | ||
310 | if (!Array.isArray(objs)) return objs | 310 | if (!Array.isArray(objs)) return objs |
@@ -330,7 +330,7 @@ export function reloadConfig () { | |||
330 | 330 | ||
331 | function purge () { | 331 | function purge () { |
332 | for (const fileName in require.cache) { | 332 | for (const fileName in require.cache) { |
333 | if (-1 === fileName.indexOf(directory())) { | 333 | if (fileName.indexOf(directory()) === -1) { |
334 | continue | 334 | continue |
335 | } | 335 | } |
336 | 336 | ||
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 032f63c8f..fb8ae7cd6 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -4,7 +4,7 @@ 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, root, parseDurationToMs } 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 = 470 | 17 | const LAST_MIGRATION_VERSION = 480 |
18 | 18 | ||
19 | // --------------------------------------------------------------------------- | 19 | // --------------------------------------------------------------------------- |
20 | 20 | ||
@@ -73,7 +73,9 @@ const SORTABLE_COLUMNS = { | |||
73 | 73 | ||
74 | PLUGINS: [ 'name', 'createdAt', 'updatedAt' ], | 74 | PLUGINS: [ 'name', 'createdAt', 'updatedAt' ], |
75 | 75 | ||
76 | AVAILABLE_PLUGINS: [ 'npmName', 'popularity' ] | 76 | AVAILABLE_PLUGINS: [ 'npmName', 'popularity' ], |
77 | |||
78 | VIDEO_REDUNDANCIES: [ 'name' ] | ||
77 | } | 79 | } |
78 | 80 | ||
79 | const OAUTH_LIFETIME = { | 81 | const OAUTH_LIFETIME = { |
@@ -117,45 +119,44 @@ const REMOTE_SCHEME = { | |||
117 | WS: 'wss' | 119 | WS: 'wss' |
118 | } | 120 | } |
119 | 121 | ||
120 | // TODO: remove 'video-file' | 122 | const JOB_ATTEMPTS: { [id in JobType]: number } = { |
121 | const JOB_ATTEMPTS: { [id in (JobType | 'video-file')]: number } = { | ||
122 | 'activitypub-http-broadcast': 5, | 123 | 'activitypub-http-broadcast': 5, |
123 | 'activitypub-http-unicast': 5, | 124 | 'activitypub-http-unicast': 5, |
124 | 'activitypub-http-fetcher': 5, | 125 | 'activitypub-http-fetcher': 5, |
125 | 'activitypub-follow': 5, | 126 | 'activitypub-follow': 5, |
126 | 'video-file-import': 1, | 127 | 'video-file-import': 1, |
127 | 'video-transcoding': 1, | 128 | 'video-transcoding': 1, |
128 | 'video-file': 1, | ||
129 | 'video-import': 1, | 129 | 'video-import': 1, |
130 | 'email': 5, | 130 | 'email': 5, |
131 | 'videos-views': 1, | 131 | 'videos-views': 1, |
132 | 'activitypub-refresher': 1 | 132 | 'activitypub-refresher': 1, |
133 | 'video-redundancy': 1 | ||
133 | } | 134 | } |
134 | const JOB_CONCURRENCY: { [id in (JobType | 'video-file')]: number } = { | 135 | const JOB_CONCURRENCY: { [id in JobType]: number } = { |
135 | 'activitypub-http-broadcast': 1, | 136 | 'activitypub-http-broadcast': 1, |
136 | 'activitypub-http-unicast': 5, | 137 | 'activitypub-http-unicast': 5, |
137 | 'activitypub-http-fetcher': 1, | 138 | 'activitypub-http-fetcher': 1, |
138 | 'activitypub-follow': 1, | 139 | 'activitypub-follow': 1, |
139 | 'video-file-import': 1, | 140 | 'video-file-import': 1, |
140 | 'video-transcoding': 1, | 141 | 'video-transcoding': 1, |
141 | 'video-file': 1, | ||
142 | 'video-import': 1, | 142 | 'video-import': 1, |
143 | 'email': 5, | 143 | 'email': 5, |
144 | 'videos-views': 1, | 144 | 'videos-views': 1, |
145 | 'activitypub-refresher': 1 | 145 | 'activitypub-refresher': 1, |
146 | 'video-redundancy': 1 | ||
146 | } | 147 | } |
147 | const JOB_TTL: { [id in (JobType | 'video-file')]: number } = { | 148 | const JOB_TTL: { [id in JobType]: number } = { |
148 | 'activitypub-http-broadcast': 60000 * 10, // 10 minutes | 149 | 'activitypub-http-broadcast': 60000 * 10, // 10 minutes |
149 | 'activitypub-http-unicast': 60000 * 10, // 10 minutes | 150 | 'activitypub-http-unicast': 60000 * 10, // 10 minutes |
150 | 'activitypub-http-fetcher': 60000 * 10, // 10 minutes | 151 | 'activitypub-http-fetcher': 60000 * 10, // 10 minutes |
151 | 'activitypub-follow': 60000 * 10, // 10 minutes | 152 | 'activitypub-follow': 60000 * 10, // 10 minutes |
152 | 'video-file-import': 1000 * 3600, // 1 hour | 153 | 'video-file-import': 1000 * 3600, // 1 hour |
153 | 'video-transcoding': 1000 * 3600 * 48, // 2 days, transcoding could be long | 154 | 'video-transcoding': 1000 * 3600 * 48, // 2 days, transcoding could be long |
154 | 'video-file': 1000 * 3600 * 48, // 2 days, transcoding could be long | ||
155 | 'video-import': 1000 * 3600 * 2, // hours | 155 | 'video-import': 1000 * 3600 * 2, // hours |
156 | 'email': 60000 * 10, // 10 minutes | 156 | 'email': 60000 * 10, // 10 minutes |
157 | 'videos-views': undefined, // Unlimited | 157 | 'videos-views': undefined, // Unlimited |
158 | 'activitypub-refresher': 60000 * 10 // 10 minutes | 158 | 'activitypub-refresher': 60000 * 10, // 10 minutes |
159 | 'video-redundancy': 1000 * 3600 * 3 // 3 hours | ||
159 | } | 160 | } |
160 | const REPEAT_JOBS: { [ id: string ]: EveryRepeatOptions | CronRepeatOptions } = { | 161 | const REPEAT_JOBS: { [ id: string ]: EveryRepeatOptions | CronRepeatOptions } = { |
161 | 'videos-views': { | 162 | 'videos-views': { |
@@ -309,6 +310,8 @@ let CONTACT_FORM_LIFETIME = 60000 * 60 // 1 hour | |||
309 | 310 | ||
310 | const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = { | 311 | const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = { |
311 | MIN: 10, | 312 | MIN: 10, |
313 | STANDARD: [ 24, 25, 30 ], | ||
314 | HD_STANDARD: [ 50, 60 ], | ||
312 | AVERAGE: 30, | 315 | AVERAGE: 30, |
313 | MAX: 60, | 316 | MAX: 60, |
314 | KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum) | 317 | KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum) |
@@ -358,42 +361,42 @@ const VIDEO_LICENCES = { | |||
358 | 7: 'Public Domain Dedication' | 361 | 7: 'Public Domain Dedication' |
359 | } | 362 | } |
360 | 363 | ||
361 | let VIDEO_LANGUAGES: { [id: string]: string } = {} | 364 | const VIDEO_LANGUAGES: { [id: string]: string } = {} |
362 | 365 | ||
363 | const VIDEO_PRIVACIES = { | 366 | const VIDEO_PRIVACIES = { |
364 | [ VideoPrivacy.PUBLIC ]: 'Public', | 367 | [VideoPrivacy.PUBLIC]: 'Public', |
365 | [ VideoPrivacy.UNLISTED ]: 'Unlisted', | 368 | [VideoPrivacy.UNLISTED]: 'Unlisted', |
366 | [ VideoPrivacy.PRIVATE ]: 'Private', | 369 | [VideoPrivacy.PRIVATE]: 'Private', |
367 | [ VideoPrivacy.INTERNAL ]: 'Internal' | 370 | [VideoPrivacy.INTERNAL]: 'Internal' |
368 | } | 371 | } |
369 | 372 | ||
370 | const VIDEO_STATES = { | 373 | const VIDEO_STATES = { |
371 | [ VideoState.PUBLISHED ]: 'Published', | 374 | [VideoState.PUBLISHED]: 'Published', |
372 | [ VideoState.TO_TRANSCODE ]: 'To transcode', | 375 | [VideoState.TO_TRANSCODE]: 'To transcode', |
373 | [ VideoState.TO_IMPORT ]: 'To import' | 376 | [VideoState.TO_IMPORT]: 'To import' |
374 | } | 377 | } |
375 | 378 | ||
376 | const VIDEO_IMPORT_STATES = { | 379 | const VIDEO_IMPORT_STATES = { |
377 | [ VideoImportState.FAILED ]: 'Failed', | 380 | [VideoImportState.FAILED]: 'Failed', |
378 | [ VideoImportState.PENDING ]: 'Pending', | 381 | [VideoImportState.PENDING]: 'Pending', |
379 | [ VideoImportState.SUCCESS ]: 'Success' | 382 | [VideoImportState.SUCCESS]: 'Success' |
380 | } | 383 | } |
381 | 384 | ||
382 | const VIDEO_ABUSE_STATES = { | 385 | const VIDEO_ABUSE_STATES = { |
383 | [ VideoAbuseState.PENDING ]: 'Pending', | 386 | [VideoAbuseState.PENDING]: 'Pending', |
384 | [ VideoAbuseState.REJECTED ]: 'Rejected', | 387 | [VideoAbuseState.REJECTED]: 'Rejected', |
385 | [ VideoAbuseState.ACCEPTED ]: 'Accepted' | 388 | [VideoAbuseState.ACCEPTED]: 'Accepted' |
386 | } | 389 | } |
387 | 390 | ||
388 | const VIDEO_PLAYLIST_PRIVACIES = { | 391 | const VIDEO_PLAYLIST_PRIVACIES = { |
389 | [ VideoPlaylistPrivacy.PUBLIC ]: 'Public', | 392 | [VideoPlaylistPrivacy.PUBLIC]: 'Public', |
390 | [ VideoPlaylistPrivacy.UNLISTED ]: 'Unlisted', | 393 | [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted', |
391 | [ VideoPlaylistPrivacy.PRIVATE ]: 'Private' | 394 | [VideoPlaylistPrivacy.PRIVATE]: 'Private' |
392 | } | 395 | } |
393 | 396 | ||
394 | const VIDEO_PLAYLIST_TYPES = { | 397 | const VIDEO_PLAYLIST_TYPES = { |
395 | [ VideoPlaylistType.REGULAR ]: 'Regular', | 398 | [VideoPlaylistType.REGULAR]: 'Regular', |
396 | [ VideoPlaylistType.WATCH_LATER ]: 'Watch later' | 399 | [VideoPlaylistType.WATCH_LATER]: 'Watch later' |
397 | } | 400 | } |
398 | 401 | ||
399 | const MIMETYPES = { | 402 | const MIMETYPES = { |
@@ -530,7 +533,7 @@ const LAZY_STATIC_PATHS = { | |||
530 | } | 533 | } |
531 | 534 | ||
532 | // Cache control | 535 | // Cache control |
533 | let STATIC_MAX_AGE = { | 536 | const STATIC_MAX_AGE = { |
534 | SERVER: '2h', | 537 | SERVER: '2h', |
535 | CLIENT: '30d' | 538 | CLIENT: '30d' |
536 | } | 539 | } |
@@ -538,11 +541,13 @@ let STATIC_MAX_AGE = { | |||
538 | // Videos thumbnail size | 541 | // Videos thumbnail size |
539 | const THUMBNAILS_SIZE = { | 542 | const THUMBNAILS_SIZE = { |
540 | width: 223, | 543 | width: 223, |
541 | height: 122 | 544 | height: 122, |
545 | minWidth: 150 | ||
542 | } | 546 | } |
543 | const PREVIEWS_SIZE = { | 547 | const PREVIEWS_SIZE = { |
544 | width: 850, | 548 | width: 850, |
545 | height: 480 | 549 | height: 480, |
550 | minWidth: 400 | ||
546 | } | 551 | } |
547 | const AVATARS_SIZE = { | 552 | const AVATARS_SIZE = { |
548 | width: 120, | 553 | width: 120, |
@@ -666,14 +671,14 @@ if (isTestInstance() === true) { | |||
666 | SCHEDULER_INTERVALS_MS.removeOldViews = 5000 | 671 | SCHEDULER_INTERVALS_MS.removeOldViews = 5000 |
667 | SCHEDULER_INTERVALS_MS.updateVideos = 5000 | 672 | SCHEDULER_INTERVALS_MS.updateVideos = 5000 |
668 | SCHEDULER_INTERVALS_MS.autoFollowIndexInstances = 5000 | 673 | SCHEDULER_INTERVALS_MS.autoFollowIndexInstances = 5000 |
669 | REPEAT_JOBS[ 'videos-views' ] = { every: 5000 } | 674 | REPEAT_JOBS['videos-views'] = { every: 5000 } |
670 | 675 | ||
671 | REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1 | 676 | REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1 |
672 | 677 | ||
673 | VIDEO_VIEW_LIFETIME = 1000 // 1 second | 678 | VIDEO_VIEW_LIFETIME = 1000 // 1 second |
674 | CONTACT_FORM_LIFETIME = 1000 // 1 second | 679 | CONTACT_FORM_LIFETIME = 1000 // 1 second |
675 | 680 | ||
676 | JOB_ATTEMPTS[ 'email' ] = 1 | 681 | JOB_ATTEMPTS['email'] = 1 |
677 | 682 | ||
678 | FILES_CACHE.VIDEO_CAPTIONS.MAX_AGE = 3000 | 683 | FILES_CACHE.VIDEO_CAPTIONS.MAX_AGE = 3000 |
679 | MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1 | 684 | MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1 |
@@ -833,42 +838,42 @@ function loadLanguages () { | |||
833 | function buildLanguages () { | 838 | function buildLanguages () { |
834 | const iso639 = require('iso-639-3') | 839 | const iso639 = require('iso-639-3') |
835 | 840 | ||
836 | const languages: { [ id: string ]: string } = {} | 841 | const languages: { [id: string]: string } = {} |
837 | 842 | ||
838 | const additionalLanguages = { | 843 | const additionalLanguages = { |
839 | 'sgn': true, // Sign languages (macro language) | 844 | sgn: true, // Sign languages (macro language) |
840 | 'ase': true, // American sign language | 845 | ase: true, // American sign language |
841 | 'sdl': true, // Arabian sign language | 846 | sdl: true, // Arabian sign language |
842 | 'bfi': true, // British sign language | 847 | bfi: true, // British sign language |
843 | 'bzs': true, // Brazilian sign language | 848 | bzs: true, // Brazilian sign language |
844 | 'csl': true, // Chinese sign language | 849 | csl: true, // Chinese sign language |
845 | 'cse': true, // Czech sign language | 850 | cse: true, // Czech sign language |
846 | 'dsl': true, // Danish sign language | 851 | dsl: true, // Danish sign language |
847 | 'fsl': true, // French sign language | 852 | fsl: true, // French sign language |
848 | 'gsg': true, // German sign language | 853 | gsg: true, // German sign language |
849 | 'pks': true, // Pakistan sign language | 854 | pks: true, // Pakistan sign language |
850 | 'jsl': true, // Japanese sign language | 855 | jsl: true, // Japanese sign language |
851 | 'sfs': true, // South African sign language | 856 | sfs: true, // South African sign language |
852 | 'swl': true, // Swedish sign language | 857 | swl: true, // Swedish sign language |
853 | 'rsl': true, // Russian sign language: true | 858 | rsl: true, // Russian sign language: true |
854 | 859 | ||
855 | 'epo': true, // Esperanto | 860 | epo: true, // Esperanto |
856 | 'tlh': true, // Klingon | 861 | tlh: true, // Klingon |
857 | 'jbo': true, // Lojban | 862 | jbo: true, // Lojban |
858 | 'avk': true // Kotava | 863 | avk: true // Kotava |
859 | } | 864 | } |
860 | 865 | ||
861 | // Only add ISO639-1 languages and some sign languages (ISO639-3) | 866 | // Only add ISO639-1 languages and some sign languages (ISO639-3) |
862 | iso639 | 867 | iso639 |
863 | .filter(l => { | 868 | .filter(l => { |
864 | return (l.iso6391 !== null && l.type === 'living') || | 869 | return (l.iso6391 !== null && l.type === 'living') || |
865 | additionalLanguages[ l.iso6393 ] === true | 870 | additionalLanguages[l.iso6393] === true |
866 | }) | 871 | }) |
867 | .forEach(l => languages[ l.iso6391 || l.iso6393 ] = l.name) | 872 | .forEach(l => { languages[l.iso6391 || l.iso6393] = l.name }) |
868 | 873 | ||
869 | // Override Occitan label | 874 | // Override Occitan label |
870 | languages[ 'oc' ] = 'Occitan' | 875 | languages['oc'] = 'Occitan' |
871 | languages[ 'el' ] = 'Greek' | 876 | languages['el'] = 'Greek' |
872 | 877 | ||
873 | return languages | 878 | return languages |
874 | } | 879 | } |
diff --git a/server/initializers/database.ts b/server/initializers/database.ts index 9ec146ab1..eedaf3c4e 100644 --- a/server/initializers/database.ts +++ b/server/initializers/database.ts | |||
@@ -119,8 +119,6 @@ async function initDatabaseModels (silent: boolean) { | |||
119 | await createFunctions() | 119 | await createFunctions() |
120 | 120 | ||
121 | if (!silent) logger.info('Database %s is ready.', dbname) | 121 | if (!silent) logger.info('Database %s is ready.', dbname) |
122 | |||
123 | return | ||
124 | } | 122 | } |
125 | 123 | ||
126 | // --------------------------------------------------------------------------- | 124 | // --------------------------------------------------------------------------- |
diff --git a/server/initializers/migrations/0005-email-pod.ts b/server/initializers/migrations/0005-email-pod.ts index c34a12255..417c33b1f 100644 --- a/server/initializers/migrations/0005-email-pod.ts +++ b/server/initializers/migrations/0005-email-pod.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0010-email-user.ts b/server/initializers/migrations/0010-email-user.ts index 37a7b0bb3..f7d01f6d6 100644 --- a/server/initializers/migrations/0010-email-user.ts +++ b/server/initializers/migrations/0010-email-user.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0015-video-views.ts b/server/initializers/migrations/0015-video-views.ts index 25164ff4d..47dd4069b 100644 --- a/server/initializers/migrations/0015-video-views.ts +++ b/server/initializers/migrations/0015-video-views.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0020-video-likes.ts b/server/initializers/migrations/0020-video-likes.ts index 945be5a98..44333f3b0 100644 --- a/server/initializers/migrations/0020-video-likes.ts +++ b/server/initializers/migrations/0020-video-likes.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0025-video-dislikes.ts b/server/initializers/migrations/0025-video-dislikes.ts index 27144c437..2aa22e2d7 100644 --- a/server/initializers/migrations/0025-video-dislikes.ts +++ b/server/initializers/migrations/0025-video-dislikes.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0030-video-category.ts b/server/initializers/migrations/0030-video-category.ts index f784f820d..00cd2d8cf 100644 --- a/server/initializers/migrations/0030-video-category.ts +++ b/server/initializers/migrations/0030-video-category.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0035-video-licence.ts b/server/initializers/migrations/0035-video-licence.ts index 3d0b0bac9..61d666c5e 100644 --- a/server/initializers/migrations/0035-video-licence.ts +++ b/server/initializers/migrations/0035-video-licence.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0040-video-nsfw.ts b/server/initializers/migrations/0040-video-nsfw.ts index f7f70d3c4..44aec8a6c 100644 --- a/server/initializers/migrations/0040-video-nsfw.ts +++ b/server/initializers/migrations/0040-video-nsfw.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0045-user-display-nsfw.ts b/server/initializers/migrations/0045-user-display-nsfw.ts index aef420f0e..07795bd75 100644 --- a/server/initializers/migrations/0045-user-display-nsfw.ts +++ b/server/initializers/migrations/0045-user-display-nsfw.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0050-video-language.ts b/server/initializers/migrations/0050-video-language.ts index 796fa5f95..6f90abb44 100644 --- a/server/initializers/migrations/0050-video-language.ts +++ b/server/initializers/migrations/0050-video-language.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0055-video-uuid.ts b/server/initializers/migrations/0055-video-uuid.ts index e0f904080..8a58aebb8 100644 --- a/server/initializers/migrations/0055-video-uuid.ts +++ b/server/initializers/migrations/0055-video-uuid.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0060-video-file.ts b/server/initializers/migrations/0060-video-file.ts index c362cf71a..00647e60e 100644 --- a/server/initializers/migrations/0060-video-file.ts +++ b/server/initializers/migrations/0060-video-file.ts | |||
@@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize, | 7 | sequelize: Sequelize.Sequelize |
8 | db: any | 8 | db: any |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0065-video-file-size.ts b/server/initializers/migrations/0065-video-file-size.ts index e9ce77e50..0bdc675c2 100644 --- a/server/initializers/migrations/0065-video-file-size.ts +++ b/server/initializers/migrations/0065-video-file-size.ts | |||
@@ -5,9 +5,9 @@ import { VideoModel } from '../../models/video/video' | |||
5 | import { getVideoFilePath } from '@server/lib/video-paths' | 5 | import { getVideoFilePath } from '@server/lib/video-paths' |
6 | 6 | ||
7 | function up (utils: { | 7 | function up (utils: { |
8 | transaction: Sequelize.Transaction, | 8 | transaction: Sequelize.Transaction |
9 | queryInterface: Sequelize.QueryInterface, | 9 | queryInterface: Sequelize.QueryInterface |
10 | sequelize: Sequelize.Sequelize, | 10 | sequelize: Sequelize.Sequelize |
11 | db: any | 11 | db: any |
12 | }): Promise<void> { | 12 | }): Promise<void> { |
13 | return utils.db.Video.listOwnedAndPopulateAuthorAndTags() | 13 | return utils.db.Video.listOwnedAndPopulateAuthorAndTags() |
diff --git a/server/initializers/migrations/0070-user-video-quota.ts b/server/initializers/migrations/0070-user-video-quota.ts index 37683432f..1d073f244 100644 --- a/server/initializers/migrations/0070-user-video-quota.ts +++ b/server/initializers/migrations/0070-user-video-quota.ts | |||
@@ -3,9 +3,9 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize, | 8 | sequelize: Sequelize.Sequelize |
9 | db: any | 9 | db: any |
10 | }): Promise<void> { | 10 | }): Promise<void> { |
11 | const q = utils.queryInterface | 11 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0075-video-resolutions.ts b/server/initializers/migrations/0075-video-resolutions.ts index e4f26cb77..f56c1b2c3 100644 --- a/server/initializers/migrations/0075-video-resolutions.ts +++ b/server/initializers/migrations/0075-video-resolutions.ts | |||
@@ -5,9 +5,9 @@ import { getVideoFileResolution } from '../../helpers/ffmpeg-utils' | |||
5 | import { readdir, rename } from 'fs-extra' | 5 | import { readdir, rename } from 'fs-extra' |
6 | 6 | ||
7 | function up (utils: { | 7 | function up (utils: { |
8 | transaction: Sequelize.Transaction, | 8 | transaction: Sequelize.Transaction |
9 | queryInterface: Sequelize.QueryInterface, | 9 | queryInterface: Sequelize.QueryInterface |
10 | sequelize: Sequelize.Sequelize, | 10 | sequelize: Sequelize.Sequelize |
11 | db: any | 11 | db: any |
12 | }): Promise<void> { | 12 | }): Promise<void> { |
13 | const torrentDir = CONFIG.STORAGE.TORRENTS_DIR | 13 | const torrentDir = CONFIG.STORAGE.TORRENTS_DIR |
diff --git a/server/initializers/migrations/0080-video-channels.ts b/server/initializers/migrations/0080-video-channels.ts index 5512bdcf1..b8e9bd6d0 100644 --- a/server/initializers/migrations/0080-video-channels.ts +++ b/server/initializers/migrations/0080-video-channels.ts | |||
@@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as uuidv4 from 'uuid/v4' | 2 | import * as uuidv4 from 'uuid/v4' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize, | 7 | sequelize: Sequelize.Sequelize |
8 | db: any | 8 | db: any |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0085-user-role.ts b/server/initializers/migrations/0085-user-role.ts index de75faec2..ec7428fd5 100644 --- a/server/initializers/migrations/0085-user-role.ts +++ b/server/initializers/migrations/0085-user-role.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0090-videos-description.ts b/server/initializers/migrations/0090-videos-description.ts index 6f98dcade..32e518d75 100644 --- a/server/initializers/migrations/0090-videos-description.ts +++ b/server/initializers/migrations/0090-videos-description.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0095-videos-privacy.ts b/server/initializers/migrations/0095-videos-privacy.ts index 4c2bf91d0..c732d6f6a 100644 --- a/server/initializers/migrations/0095-videos-privacy.ts +++ b/server/initializers/migrations/0095-videos-privacy.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0100-activitypub.ts b/server/initializers/migrations/0100-activitypub.ts index 96d44a7ce..05fd37406 100644 --- a/server/initializers/migrations/0100-activitypub.ts +++ b/server/initializers/migrations/0100-activitypub.ts | |||
@@ -7,9 +7,9 @@ import { ApplicationModel } from '../../models/application/application' | |||
7 | import { SERVER_ACTOR_NAME } from '../constants' | 7 | import { SERVER_ACTOR_NAME } from '../constants' |
8 | 8 | ||
9 | async function up (utils: { | 9 | async function up (utils: { |
10 | transaction: Sequelize.Transaction, | 10 | transaction: Sequelize.Transaction |
11 | queryInterface: Sequelize.QueryInterface, | 11 | queryInterface: Sequelize.QueryInterface |
12 | sequelize: Sequelize.Sequelize, | 12 | sequelize: Sequelize.Sequelize |
13 | db: any | 13 | db: any |
14 | }): Promise<void> { | 14 | }): Promise<void> { |
15 | const q = utils.queryInterface | 15 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0105-server-mail.ts b/server/initializers/migrations/0105-server-mail.ts index 4b9600e91..5ee37c418 100644 --- a/server/initializers/migrations/0105-server-mail.ts +++ b/server/initializers/migrations/0105-server-mail.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.queryInterface.removeColumn('Servers', 'email') | 9 | await utils.queryInterface.removeColumn('Servers', 'email') |
diff --git a/server/initializers/migrations/0110-server-key.ts b/server/initializers/migrations/0110-server-key.ts index 5ff6daf69..354cd7e76 100644 --- a/server/initializers/migrations/0110-server-key.ts +++ b/server/initializers/migrations/0110-server-key.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.queryInterface.removeColumn('Servers', 'publicKey') | 9 | await utils.queryInterface.removeColumn('Servers', 'publicKey') |
diff --git a/server/initializers/migrations/0115-account-avatar.ts b/server/initializers/migrations/0115-account-avatar.ts index b318e8163..604b6394a 100644 --- a/server/initializers/migrations/0115-account-avatar.ts +++ b/server/initializers/migrations/0115-account-avatar.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.db.Avatar.sync() | 9 | await utils.db.Avatar.sync() |
diff --git a/server/initializers/migrations/0120-video-null.ts b/server/initializers/migrations/0120-video-null.ts index 6d253f04f..1b407b270 100644 --- a/server/initializers/migrations/0120-video-null.ts +++ b/server/initializers/migrations/0120-video-null.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | 9 | ||
diff --git a/server/initializers/migrations/0125-table-lowercase.ts b/server/initializers/migrations/0125-table-lowercase.ts index 78041ccb0..f75a56791 100644 --- a/server/initializers/migrations/0125-table-lowercase.ts +++ b/server/initializers/migrations/0125-table-lowercase.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | await utils.queryInterface.renameTable('Applications', 'application') | 8 | await utils.queryInterface.renameTable('Applications', 'application') |
diff --git a/server/initializers/migrations/0130-user-autoplay-video.ts b/server/initializers/migrations/0130-user-autoplay-video.ts index 9f6878e39..d57934588 100644 --- a/server/initializers/migrations/0130-user-autoplay-video.ts +++ b/server/initializers/migrations/0130-user-autoplay-video.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0135-video-channel-actor.ts b/server/initializers/migrations/0135-video-channel-actor.ts index 5ace0f4d2..c0c343384 100644 --- a/server/initializers/migrations/0135-video-channel-actor.ts +++ b/server/initializers/migrations/0135-video-channel-actor.ts | |||
@@ -3,8 +3,8 @@ import { DataType } from 'sequelize-typescript' | |||
3 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' | 3 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' |
4 | 4 | ||
5 | async function up (utils: { | 5 | async function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | // Create actor table | 10 | // Create actor table |
@@ -64,10 +64,10 @@ async function up (utils: { | |||
64 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 64 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
65 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 65 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
66 | ) | 66 | ) |
67 | SELECT | 67 | SELECT |
68 | 'Application', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 68 | 'Application', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
69 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 69 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
70 | FROM account | 70 | FROM account |
71 | WHERE "applicationId" IS NOT NULL | 71 | WHERE "applicationId" IS NOT NULL |
72 | ` | 72 | ` |
73 | await utils.sequelize.query(query1) | 73 | await utils.sequelize.query(query1) |
@@ -79,10 +79,10 @@ async function up (utils: { | |||
79 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 79 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
80 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 80 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
81 | ) | 81 | ) |
82 | SELECT | 82 | SELECT |
83 | 'Person', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 83 | 'Person', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
84 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 84 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
85 | FROM account | 85 | FROM account |
86 | WHERE "applicationId" IS NULL | 86 | WHERE "applicationId" IS NULL |
87 | ` | 87 | ` |
88 | await utils.sequelize.query(query2) | 88 | await utils.sequelize.query(query2) |
@@ -108,17 +108,17 @@ async function up (utils: { | |||
108 | } | 108 | } |
109 | 109 | ||
110 | { | 110 | { |
111 | const query = ` | 111 | const query = ` |
112 | INSERT INTO actor | 112 | INSERT INTO actor |
113 | ( | 113 | ( |
114 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 114 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
115 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 115 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
116 | ) | 116 | ) |
117 | SELECT | 117 | SELECT |
118 | 'Group', "videoChannel".uuid, "videoChannel".uuid, "videoChannel".url, null, null, 0, 0, "videoChannel".url || '/inbox', | 118 | 'Group', "videoChannel".uuid, "videoChannel".uuid, "videoChannel".url, null, null, 0, 0, "videoChannel".url || '/inbox', |
119 | "videoChannel".url || '/outbox', "videoChannel".url || '/inbox', "videoChannel".url || '/followers', "videoChannel".url || '/following', | 119 | "videoChannel".url || '/outbox', "videoChannel".url || '/inbox', "videoChannel".url || '/followers', "videoChannel".url || '/following', |
120 | null, account."serverId", "videoChannel"."createdAt", "videoChannel"."updatedAt" | 120 | null, account."serverId", "videoChannel"."createdAt", "videoChannel"."updatedAt" |
121 | FROM "videoChannel" | 121 | FROM "videoChannel" |
122 | INNER JOIN "account" on "videoChannel"."accountId" = "account".id | 122 | INNER JOIN "account" on "videoChannel"."accountId" = "account".id |
123 | ` | 123 | ` |
124 | await utils.sequelize.query(query) | 124 | await utils.sequelize.query(query) |
@@ -157,13 +157,13 @@ async function up (utils: { | |||
157 | } | 157 | } |
158 | 158 | ||
159 | { | 159 | { |
160 | const query1 = `UPDATE "actorFollow" | 160 | const query1 = `UPDATE "actorFollow" |
161 | SET "actorId" = | 161 | SET "actorId" = |
162 | (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."actorId")` | 162 | (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."actorId")` |
163 | await utils.sequelize.query(query1) | 163 | await utils.sequelize.query(query1) |
164 | 164 | ||
165 | const query2 = `UPDATE "actorFollow" | 165 | const query2 = `UPDATE "actorFollow" |
166 | SET "targetActorId" = | 166 | SET "targetActorId" = |
167 | (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."targetActorId")` | 167 | (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."targetActorId")` |
168 | 168 | ||
169 | await utils.sequelize.query(query2) | 169 | await utils.sequelize.query(query2) |
@@ -189,8 +189,8 @@ async function up (utils: { | |||
189 | await utils.queryInterface.removeConstraint('videoShare', 'videoShare_accountId_fkey') | 189 | await utils.queryInterface.removeConstraint('videoShare', 'videoShare_accountId_fkey') |
190 | } | 190 | } |
191 | 191 | ||
192 | const query = `UPDATE "videoShare" | 192 | const query = `UPDATE "videoShare" |
193 | SET "actorId" = | 193 | SET "actorId" = |
194 | (SELECT "actorId" FROM account WHERE id = "videoShare"."actorId")` | 194 | (SELECT "actorId" FROM account WHERE id = "videoShare"."actorId")` |
195 | await utils.sequelize.query(query) | 195 | await utils.sequelize.query(query) |
196 | 196 | ||
diff --git a/server/initializers/migrations/0140-actor-url.ts b/server/initializers/migrations/0140-actor-url.ts index 020499391..d790988ad 100644 --- a/server/initializers/migrations/0140-actor-url.ts +++ b/server/initializers/migrations/0140-actor-url.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import { WEBSERVER } from '../constants' | 2 | import { WEBSERVER } from '../constants' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const toReplace = WEBSERVER.HOSTNAME + ':443' | 9 | const toReplace = WEBSERVER.HOSTNAME + ':443' |
diff --git a/server/initializers/migrations/0145-delete-author.ts b/server/initializers/migrations/0145-delete-author.ts index cb23d1cc2..6c9427997 100644 --- a/server/initializers/migrations/0145-delete-author.ts +++ b/server/initializers/migrations/0145-delete-author.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | await utils.queryInterface.dropTable('Authors') | 8 | await utils.queryInterface.dropTable('Authors') |
diff --git a/server/initializers/migrations/0150-avatar-cascade.ts b/server/initializers/migrations/0150-avatar-cascade.ts index 821696717..fb3b25773 100644 --- a/server/initializers/migrations/0150-avatar-cascade.ts +++ b/server/initializers/migrations/0150-avatar-cascade.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | await utils.queryInterface.removeConstraint('actor', 'actor_avatarId_fkey') | 8 | await utils.queryInterface.removeConstraint('actor', 'actor_avatarId_fkey') |
diff --git a/server/initializers/migrations/0155-video-comments-enabled.ts b/server/initializers/migrations/0155-video-comments-enabled.ts index 6949d3a0c..691640b35 100644 --- a/server/initializers/migrations/0155-video-comments-enabled.ts +++ b/server/initializers/migrations/0155-video-comments-enabled.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import { Migration } from '../../models/migrations' | 2 | import { Migration } from '../../models/migrations' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0160-account-route.ts b/server/initializers/migrations/0160-account-route.ts index cab4c72f1..97469948b 100644 --- a/server/initializers/migrations/0160-account-route.ts +++ b/server/initializers/migrations/0160-account-route.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0165-video-route.ts b/server/initializers/migrations/0165-video-route.ts index 56d98bc69..aa7c75128 100644 --- a/server/initializers/migrations/0165-video-route.ts +++ b/server/initializers/migrations/0165-video-route.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0170-actor-follow-score.ts b/server/initializers/migrations/0170-actor-follow-score.ts index a12b35da9..901a3c799 100644 --- a/server/initializers/migrations/0170-actor-follow-score.ts +++ b/server/initializers/migrations/0170-actor-follow-score.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import { ACTOR_FOLLOW_SCORE } from '../constants' | 2 | import { ACTOR_FOLLOW_SCORE } from '../constants' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.queryInterface.removeColumn('server', 'score') | 9 | await utils.queryInterface.removeColumn('server', 'score') |
diff --git a/server/initializers/migrations/0175-actor-follow-counts.ts b/server/initializers/migrations/0175-actor-follow-counts.ts index 4fb524181..d7853f8dc 100644 --- a/server/initializers/migrations/0175-actor-follow-counts.ts +++ b/server/initializers/migrations/0175-actor-follow-counts.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | const query = 'UPDATE "actor" SET ' + | 8 | const query = 'UPDATE "actor" SET ' + |
diff --git a/server/initializers/migrations/0180-job-table-delete.ts b/server/initializers/migrations/0180-job-table-delete.ts index df29145d0..fb48a0c9d 100644 --- a/server/initializers/migrations/0180-job-table-delete.ts +++ b/server/initializers/migrations/0180-job-table-delete.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | await utils.queryInterface.dropTable('job') | 8 | await utils.queryInterface.dropTable('job') |
diff --git a/server/initializers/migrations/0185-video-share-url.ts b/server/initializers/migrations/0185-video-share-url.ts index f7eeb0878..f59931e0f 100644 --- a/server/initializers/migrations/0185-video-share-url.ts +++ b/server/initializers/migrations/0185-video-share-url.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0190-video-comment-unique-url.ts b/server/initializers/migrations/0190-video-comment-unique-url.ts index b196c9352..a8769ed41 100644 --- a/server/initializers/migrations/0190-video-comment-unique-url.ts +++ b/server/initializers/migrations/0190-video-comment-unique-url.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0195-support.ts b/server/initializers/migrations/0195-support.ts index 3b9eabe79..3f7c75dce 100644 --- a/server/initializers/migrations/0195-support.ts +++ b/server/initializers/migrations/0195-support.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0200-video-published-at.ts b/server/initializers/migrations/0200-video-published-at.ts index 1701ea07a..d8c7b42a7 100644 --- a/server/initializers/migrations/0200-video-published-at.ts +++ b/server/initializers/migrations/0200-video-published-at.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0205-user-nsfw-policy.ts b/server/initializers/migrations/0205-user-nsfw-policy.ts index d0f6e8962..9c2786f12 100644 --- a/server/initializers/migrations/0205-user-nsfw-policy.ts +++ b/server/initializers/migrations/0205-user-nsfw-policy.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0210-video-language.ts b/server/initializers/migrations/0210-video-language.ts index ca95c7527..ee4ce9266 100644 --- a/server/initializers/migrations/0210-video-language.ts +++ b/server/initializers/migrations/0210-video-language.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import { CONSTRAINTS_FIELDS } from '../constants' | 2 | import { CONSTRAINTS_FIELDS } from '../constants' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | 9 | ||
diff --git a/server/initializers/migrations/0215-video-support-length.ts b/server/initializers/migrations/0215-video-support-length.ts index ba395050f..26c0ca700 100644 --- a/server/initializers/migrations/0215-video-support-length.ts +++ b/server/initializers/migrations/0215-video-support-length.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0255-video-blacklist-reason.ts b/server/initializers/migrations/0255-video-blacklist-reason.ts index 69d6efb9e..7de982f93 100644 --- a/server/initializers/migrations/0255-video-blacklist-reason.ts +++ b/server/initializers/migrations/0255-video-blacklist-reason.ts | |||
@@ -1,5 +1,4 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import { VideoAbuseState } from '../../../shared/models/videos' | ||
3 | 2 | ||
4 | async function up (utils: { | 3 | async function up (utils: { |
5 | transaction: Sequelize.Transaction | 4 | transaction: Sequelize.Transaction |
diff --git a/server/initializers/migrations/0285-description-support.ts b/server/initializers/migrations/0285-description-support.ts index 85ef4ef39..aab3a938f 100644 --- a/server/initializers/migrations/0285-description-support.ts +++ b/server/initializers/migrations/0285-description-support.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0290-account-video-rate-url.ts b/server/initializers/migrations/0290-account-video-rate-url.ts index bdabf2929..b974b1a81 100644 --- a/server/initializers/migrations/0290-account-video-rate-url.ts +++ b/server/initializers/migrations/0290-account-video-rate-url.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0295-video-file-extname.ts b/server/initializers/migrations/0295-video-file-extname.ts index dbf249f66..e1999b072 100644 --- a/server/initializers/migrations/0295-video-file-extname.ts +++ b/server/initializers/migrations/0295-video-file-extname.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0300-user-videos-history-enabled.ts b/server/initializers/migrations/0300-user-videos-history-enabled.ts index aa5fc21fb..5e35e14ba 100644 --- a/server/initializers/migrations/0300-user-videos-history-enabled.ts +++ b/server/initializers/migrations/0300-user-videos-history-enabled.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0305-fix-unfederated-videos.ts b/server/initializers/migrations/0305-fix-unfederated-videos.ts index be206601f..9c5d56b7b 100644 --- a/server/initializers/migrations/0305-fix-unfederated-videos.ts +++ b/server/initializers/migrations/0305-fix-unfederated-videos.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0310-drop-unused-video-indexes.ts b/server/initializers/migrations/0310-drop-unused-video-indexes.ts index d51f430c0..181858d3d 100644 --- a/server/initializers/migrations/0310-drop-unused-video-indexes.ts +++ b/server/initializers/migrations/0310-drop-unused-video-indexes.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const indexNames = [ | 9 | const indexNames = [ |
diff --git a/server/initializers/migrations/0315-user-notifications.ts b/server/initializers/migrations/0315-user-notifications.ts index 8284c58a0..0e3f4fbef 100644 --- a/server/initializers/migrations/0315-user-notifications.ts +++ b/server/initializers/migrations/0315-user-notifications.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0320-blacklist-unfederate.ts b/server/initializers/migrations/0320-blacklist-unfederate.ts index 6fb7bbb90..41de41c55 100644 --- a/server/initializers/migrations/0320-blacklist-unfederate.ts +++ b/server/initializers/migrations/0320-blacklist-unfederate.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0325-video-abuse-fields.ts b/server/initializers/migrations/0325-video-abuse-fields.ts index fca6d666f..d88724a20 100644 --- a/server/initializers/migrations/0325-video-abuse-fields.ts +++ b/server/initializers/migrations/0325-video-abuse-fields.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0330-video-streaming-playlist.ts b/server/initializers/migrations/0330-video-streaming-playlist.ts index c85a762ab..f75541a7f 100644 --- a/server/initializers/migrations/0330-video-streaming-playlist.ts +++ b/server/initializers/migrations/0330-video-streaming-playlist.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0335-video-downloading-enabled.ts b/server/initializers/migrations/0335-video-downloading-enabled.ts index e79466447..c745f1f02 100644 --- a/server/initializers/migrations/0335-video-downloading-enabled.ts +++ b/server/initializers/migrations/0335-video-downloading-enabled.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import { Migration } from '../../models/migrations' | 2 | import { Migration } from '../../models/migrations' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0340-add-originally-published-at.ts b/server/initializers/migrations/0340-add-originally-published-at.ts index fe4f4a5f9..7cbc14ab5 100644 --- a/server/initializers/migrations/0340-add-originally-published-at.ts +++ b/server/initializers/migrations/0340-add-originally-published-at.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0345-video-playlists.ts b/server/initializers/migrations/0345-video-playlists.ts index de69f5b9e..76813f93f 100644 --- a/server/initializers/migrations/0345-video-playlists.ts +++ b/server/initializers/migrations/0345-video-playlists.ts | |||
@@ -4,8 +4,8 @@ import * as uuidv4 from 'uuid/v4' | |||
4 | import { WEBSERVER } from '../constants' | 4 | import { WEBSERVER } from '../constants' |
5 | 5 | ||
6 | async function up (utils: { | 6 | async function up (utils: { |
7 | transaction: Sequelize.Transaction, | 7 | transaction: Sequelize.Transaction |
8 | queryInterface: Sequelize.QueryInterface, | 8 | queryInterface: Sequelize.QueryInterface |
9 | sequelize: Sequelize.Sequelize | 9 | sequelize: Sequelize.Sequelize |
10 | }): Promise<void> { | 10 | }): Promise<void> { |
11 | const transaction = utils.transaction | 11 | const transaction = utils.transaction |
diff --git a/server/initializers/migrations/0350-video-blacklist-type.ts b/server/initializers/migrations/0350-video-blacklist-type.ts index 4849020ef..f79ae5ec7 100644 --- a/server/initializers/migrations/0350-video-blacklist-type.ts +++ b/server/initializers/migrations/0350-video-blacklist-type.ts | |||
@@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize' | |||
2 | import { VideoBlacklistType } from '../../../shared/models/videos' | 2 | import { VideoBlacklistType } from '../../../shared/models/videos' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize, | 7 | sequelize: Sequelize.Sequelize |
8 | db: any | 8 | db: any |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | { | 10 | { |
diff --git a/server/initializers/migrations/0355-p2p-peer-version.ts b/server/initializers/migrations/0355-p2p-peer-version.ts index 18f23d9b7..89af28d07 100644 --- a/server/initializers/migrations/0355-p2p-peer-version.ts +++ b/server/initializers/migrations/0355-p2p-peer-version.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | 9 | ||
diff --git a/server/initializers/migrations/0360-notification-instance-follower.ts b/server/initializers/migrations/0360-notification-instance-follower.ts index 05caf8e1d..6f9a01a9c 100644 --- a/server/initializers/migrations/0360-notification-instance-follower.ts +++ b/server/initializers/migrations/0360-notification-instance-follower.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0365-user-admin-flags.ts b/server/initializers/migrations/0365-user-admin-flags.ts index 20553100a..b705387da 100644 --- a/server/initializers/migrations/0365-user-admin-flags.ts +++ b/server/initializers/migrations/0365-user-admin-flags.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0370-thumbnail.ts b/server/initializers/migrations/0370-thumbnail.ts index 384ca1a15..07c25436a 100644 --- a/server/initializers/migrations/0370-thumbnail.ts +++ b/server/initializers/migrations/0370-thumbnail.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0375-account-description.ts b/server/initializers/migrations/0375-account-description.ts index 1258563fd..f9af942e0 100644 --- a/server/initializers/migrations/0375-account-description.ts +++ b/server/initializers/migrations/0375-account-description.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0380-cleanup-timestamps.ts b/server/initializers/migrations/0380-cleanup-timestamps.ts index 2a9fd6f02..18ecfb997 100644 --- a/server/initializers/migrations/0380-cleanup-timestamps.ts +++ b/server/initializers/migrations/0380-cleanup-timestamps.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | try { | 9 | try { |
diff --git a/server/initializers/migrations/0385-remove-actor-uuid.ts b/server/initializers/migrations/0385-remove-actor-uuid.ts index 032c0562b..eefbc386b 100644 --- a/server/initializers/migrations/0385-remove-actor-uuid.ts +++ b/server/initializers/migrations/0385-remove-actor-uuid.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.queryInterface.removeColumn('actor', 'uuid') | 9 | await utils.queryInterface.removeColumn('actor', 'uuid') |
diff --git a/server/initializers/migrations/0390-user-pending-email.ts b/server/initializers/migrations/0390-user-pending-email.ts index 5ca871746..9cf0affa5 100644 --- a/server/initializers/migrations/0390-user-pending-email.ts +++ b/server/initializers/migrations/0390-user-pending-email.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0395-user-video-languages.ts b/server/initializers/migrations/0395-user-video-languages.ts index 278698bf4..9c24fbc9a 100644 --- a/server/initializers/migrations/0395-user-video-languages.ts +++ b/server/initializers/migrations/0395-user-video-languages.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0400-user-theme.ts b/server/initializers/migrations/0400-user-theme.ts index f74d76115..7addb1bb3 100644 --- a/server/initializers/migrations/0400-user-theme.ts +++ b/server/initializers/migrations/0400-user-theme.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0405-plugin.ts b/server/initializers/migrations/0405-plugin.ts index c55b81960..5c290b986 100644 --- a/server/initializers/migrations/0405-plugin.ts +++ b/server/initializers/migrations/0405-plugin.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0410-video-playlist-element.ts b/server/initializers/migrations/0410-video-playlist-element.ts index f536632a2..1b4692357 100644 --- a/server/initializers/migrations/0410-video-playlist-element.ts +++ b/server/initializers/migrations/0410-video-playlist-element.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0415-thumbnail-auto-generated.ts b/server/initializers/migrations/0415-thumbnail-auto-generated.ts index f822a4c05..98d563c88 100644 --- a/server/initializers/migrations/0415-thumbnail-auto-generated.ts +++ b/server/initializers/migrations/0415-thumbnail-auto-generated.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0420-avatar-lazy.ts b/server/initializers/migrations/0420-avatar-lazy.ts index 5fc57aac2..5c74819d2 100644 --- a/server/initializers/migrations/0420-avatar-lazy.ts +++ b/server/initializers/migrations/0420-avatar-lazy.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0425-nullable-actor-fields.ts b/server/initializers/migrations/0425-nullable-actor-fields.ts index 4e5f9e6ab..720b99ccc 100644 --- a/server/initializers/migrations/0425-nullable-actor-fields.ts +++ b/server/initializers/migrations/0425-nullable-actor-fields.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0430-auto-follow-notification-setting.ts b/server/initializers/migrations/0430-auto-follow-notification-setting.ts index 034bdd46d..1734828a4 100644 --- a/server/initializers/migrations/0430-auto-follow-notification-setting.ts +++ b/server/initializers/migrations/0430-auto-follow-notification-setting.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0435-user-modals.ts b/server/initializers/migrations/0435-user-modals.ts index 5c2aa85b5..737440e9b 100644 --- a/server/initializers/migrations/0435-user-modals.ts +++ b/server/initializers/migrations/0435-user-modals.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0440-user-auto-play-next-video.ts b/server/initializers/migrations/0440-user-auto-play-next-video.ts index f0baafe7b..f3f663f59 100644 --- a/server/initializers/migrations/0440-user-auto-play-next-video.ts +++ b/server/initializers/migrations/0440-user-auto-play-next-video.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0445-shared-inbox-optional.ts b/server/initializers/migrations/0445-shared-inbox-optional.ts index dad2d6569..ade1a2a57 100644 --- a/server/initializers/migrations/0445-shared-inbox-optional.ts +++ b/server/initializers/migrations/0445-shared-inbox-optional.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0450-streaming-playlist-files.ts b/server/initializers/migrations/0450-streaming-playlist-files.ts index 460dac8be..08e2e3989 100644 --- a/server/initializers/migrations/0450-streaming-playlist-files.ts +++ b/server/initializers/migrations/0450-streaming-playlist-files.ts | |||
@@ -1,15 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import { join } from 'path' | ||
3 | import { HLS_STREAMING_PLAYLIST_DIRECTORY, WEBSERVER } from '@server/initializers/constants' | ||
4 | import { CONFIG } from '@server/initializers/config' | ||
5 | import { pathExists, stat, writeFile } from 'fs-extra' | ||
6 | import * as parseTorrent from 'parse-torrent' | ||
7 | import { createTorrentPromise } from '@server/helpers/webtorrent' | ||
8 | 2 | ||
9 | async function up (utils: { | 3 | async function up (utils: { |
10 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
11 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
12 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
13 | db: any | 7 | db: any |
14 | }): Promise<void> { | 8 | }): Promise<void> { |
15 | { | 9 | { |
@@ -42,8 +36,8 @@ async function up (utils: { | |||
42 | { | 36 | { |
43 | const query = 'insert into "videoFile" ' + | 37 | const query = 'insert into "videoFile" ' + |
44 | '(resolution, size, "infoHash", "videoId", "createdAt", "updatedAt", fps, extname, "videoStreamingPlaylistId")' + | 38 | '(resolution, size, "infoHash", "videoId", "createdAt", "updatedAt", fps, extname, "videoStreamingPlaylistId")' + |
45 | '(SELECT "videoFile".resolution, "videoFile".size, \'fake\', NULL, "videoFile"."createdAt", "videoFile"."updatedAt", "videoFile"."fps", ' + | 39 | '(SELECT "videoFile".resolution, "videoFile".size, \'fake\', NULL, "videoFile"."createdAt", "videoFile"."updatedAt", ' + |
46 | '"videoFile".extname, "videoStreamingPlaylist".id FROM "videoStreamingPlaylist" ' + | 40 | '"videoFile"."fps", "videoFile".extname, "videoStreamingPlaylist".id FROM "videoStreamingPlaylist" ' + |
47 | 'inner join video ON video.id = "videoStreamingPlaylist"."videoId" inner join "videoFile" ON "videoFile"."videoId" = video.id)' | 41 | 'inner join video ON video.id = "videoStreamingPlaylist"."videoId" inner join "videoFile" ON "videoFile"."videoId" = video.id)' |
48 | 42 | ||
49 | await utils.sequelize.query(query, { transaction: utils.transaction }) | 43 | await utils.sequelize.query(query, { transaction: utils.transaction }) |
diff --git a/server/initializers/migrations/0455-soft-delete-video-comments.ts b/server/initializers/migrations/0455-soft-delete-video-comments.ts index bcfb97b56..00e56015f 100644 --- a/server/initializers/migrations/0455-soft-delete-video-comments.ts +++ b/server/initializers/migrations/0455-soft-delete-video-comments.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0460-user-playlist-autoplay.ts b/server/initializers/migrations/0460-user-playlist-autoplay.ts index 3067ac1a4..d6f5081ab 100644 --- a/server/initializers/migrations/0460-user-playlist-autoplay.ts +++ b/server/initializers/migrations/0460-user-playlist-autoplay.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0465-thumbnail-file-url-length.ts b/server/initializers/migrations/0465-thumbnail-file-url-length.ts index db8c85c29..84a4fa0ba 100644 --- a/server/initializers/migrations/0465-thumbnail-file-url-length.ts +++ b/server/initializers/migrations/0465-thumbnail-file-url-length.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0470-cleaup-indexes.ts b/server/initializers/migrations/0470-cleaup-indexes.ts index 53e401c2b..7365c30f8 100644 --- a/server/initializers/migrations/0470-cleaup-indexes.ts +++ b/server/initializers/migrations/0470-cleaup-indexes.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.sequelize.query('DROP INDEX IF EXISTS video_share_account_id;') | 9 | await utils.sequelize.query('DROP INDEX IF EXISTS video_share_account_id;') |
diff --git a/server/initializers/migrations/0475-redundancy-expires-on.ts b/server/initializers/migrations/0475-redundancy-expires-on.ts new file mode 100644 index 000000000..edbddba37 --- /dev/null +++ b/server/initializers/migrations/0475-redundancy-expires-on.ts | |||
@@ -0,0 +1,27 @@ | |||
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 | { | ||
10 | const data = { | ||
11 | type: Sequelize.DATE, | ||
12 | allowNull: true, | ||
13 | defaultValue: null | ||
14 | } | ||
15 | |||
16 | await utils.queryInterface.changeColumn('videoRedundancy', 'expiresOn', data) | ||
17 | } | ||
18 | } | ||
19 | |||
20 | function down (options) { | ||
21 | throw new Error('Not implemented.') | ||
22 | } | ||
23 | |||
24 | export { | ||
25 | up, | ||
26 | down | ||
27 | } | ||
diff --git a/server/initializers/migrations/0480-caption-file-url.ts b/server/initializers/migrations/0480-caption-file-url.ts new file mode 100644 index 000000000..1f88206d3 --- /dev/null +++ b/server/initializers/migrations/0480-caption-file-url.ts | |||
@@ -0,0 +1,27 @@ | |||
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 | { | ||
10 | const data = { | ||
11 | type: Sequelize.STRING, | ||
12 | allowNull: true, | ||
13 | defaultValue: null | ||
14 | } | ||
15 | |||
16 | await utils.queryInterface.addColumn('videoCaption', 'fileUrl', data) | ||
17 | } | ||
18 | } | ||
19 | |||
20 | function down (options) { | ||
21 | throw new Error('Not implemented.') | ||
22 | } | ||
23 | |||
24 | export { | ||
25 | up, | ||
26 | down | ||
27 | } | ||
diff --git a/server/initializers/migrator.ts b/server/initializers/migrator.ts index 1cb0116b7..77203ae24 100644 --- a/server/initializers/migrator.ts +++ b/server/initializers/migrator.ts | |||
@@ -20,7 +20,7 @@ async function migrate () { | |||
20 | } | 20 | } |
21 | 21 | ||
22 | const rows = await sequelizeTypescript.query<{ migrationVersion: number }>(query, options) | 22 | const rows = await sequelizeTypescript.query<{ migrationVersion: number }>(query, options) |
23 | if (rows && rows[0] && rows[0].migrationVersion) { | 23 | if (rows?.[0]?.migrationVersion) { |
24 | actualVersion = rows[0].migrationVersion | 24 | actualVersion = rows[0].migrationVersion |
25 | } | 25 | } |
26 | 26 | ||
@@ -60,7 +60,7 @@ export { | |||
60 | async function getMigrationScripts () { | 60 | async function getMigrationScripts () { |
61 | const files = await readdir(path.join(__dirname, 'migrations')) | 61 | const files = await readdir(path.join(__dirname, 'migrations')) |
62 | const filesToMigrate: { | 62 | const filesToMigrate: { |
63 | version: string, | 63 | version: string |
64 | script: string | 64 | script: string |
65 | }[] = [] | 65 | }[] = [] |
66 | 66 | ||
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index f802658cf..3f6edc070 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { Transaction } from 'sequelize' | 2 | import { Transaction } from 'sequelize' |
3 | import * as url from 'url' | 3 | import { URL } from 'url' |
4 | import * as uuidv4 from 'uuid/v4' | 4 | 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' |
@@ -33,8 +33,7 @@ import { | |||
33 | MActorFull, | 33 | MActorFull, |
34 | MActorFullActor, | 34 | MActorFullActor, |
35 | MActorId, | 35 | MActorId, |
36 | MChannel, | 36 | MChannel |
37 | MChannelAccountDefault | ||
38 | } from '../../typings/models' | 37 | } from '../../typings/models' |
39 | 38 | ||
40 | // Set account keys, this could be long so process after the account creation and do not block the client | 39 | // Set account keys, this could be long so process after the account creation and do not block the client |
@@ -121,13 +120,13 @@ async function getOrCreateActorAndServerAndModel ( | |||
121 | 120 | ||
122 | if ((created === true || refreshed === true) && updateCollections === true) { | 121 | if ((created === true || refreshed === true) && updateCollections === true) { |
123 | const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' } | 122 | const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' } |
124 | await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) | 123 | await JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload }) |
125 | } | 124 | } |
126 | 125 | ||
127 | // We created a new account: fetch the playlists | 126 | // We created a new account: fetch the playlists |
128 | if (created === true && actor.Account && accountPlaylistsUrl) { | 127 | if (created === true && actor.Account && accountPlaylistsUrl) { |
129 | const payload = { uri: accountPlaylistsUrl, accountId: actor.Account.id, type: 'account-playlists' as 'account-playlists' } | 128 | const payload = { uri: accountPlaylistsUrl, accountId: actor.Account.id, type: 'account-playlists' as 'account-playlists' } |
130 | await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) | 129 | await JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload }) |
131 | } | 130 | } |
132 | 131 | ||
133 | return actorRefreshed | 132 | return actorRefreshed |
@@ -215,7 +214,7 @@ async function fetchActorTotalItems (url: string) { | |||
215 | } | 214 | } |
216 | } | 215 | } |
217 | 216 | ||
218 | async function getAvatarInfoIfExists (actorJSON: ActivityPubActor) { | 217 | function getAvatarInfoIfExists (actorJSON: ActivityPubActor) { |
219 | if ( | 218 | if ( |
220 | actorJSON.icon && actorJSON.icon.type === 'Image' && MIMETYPES.IMAGE.MIMETYPE_EXT[actorJSON.icon.mediaType] !== undefined && | 219 | actorJSON.icon && actorJSON.icon.type === 'Image' && MIMETYPES.IMAGE.MIMETYPE_EXT[actorJSON.icon.mediaType] !== undefined && |
221 | isActivityPubUrlValid(actorJSON.icon.url) | 220 | isActivityPubUrlValid(actorJSON.icon.url) |
@@ -271,7 +270,10 @@ async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannel | |||
271 | 270 | ||
272 | if (statusCode === 404) { | 271 | if (statusCode === 404) { |
273 | logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url) | 272 | logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url) |
274 | actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy() | 273 | actor.Account |
274 | ? await actor.Account.destroy() | ||
275 | : await actor.VideoChannel.destroy() | ||
276 | |||
275 | return { actor: undefined, refreshed: false } | 277 | return { actor: undefined, refreshed: false } |
276 | } | 278 | } |
277 | 279 | ||
@@ -337,14 +339,14 @@ function saveActorAndServerAndModelIfNotExist ( | |||
337 | ownerActor?: MActorFullActor, | 339 | ownerActor?: MActorFullActor, |
338 | t?: Transaction | 340 | t?: Transaction |
339 | ): Bluebird<MActorFullActor> | Promise<MActorFullActor> { | 341 | ): Bluebird<MActorFullActor> | Promise<MActorFullActor> { |
340 | let actor = result.actor | 342 | const actor = result.actor |
341 | 343 | ||
342 | if (t !== undefined) return save(t) | 344 | if (t !== undefined) return save(t) |
343 | 345 | ||
344 | return sequelizeTypescript.transaction(t => save(t)) | 346 | return sequelizeTypescript.transaction(t => save(t)) |
345 | 347 | ||
346 | async function save (t: Transaction) { | 348 | async function save (t: Transaction) { |
347 | const actorHost = url.parse(actor.url).host | 349 | const actorHost = new URL(actor.url).host |
348 | 350 | ||
349 | const serverOptions = { | 351 | const serverOptions = { |
350 | where: { | 352 | where: { |
@@ -402,7 +404,7 @@ type FetchRemoteActorResult = { | |||
402 | support?: string | 404 | support?: string |
403 | playlists?: string | 405 | playlists?: string |
404 | avatar?: { | 406 | avatar?: { |
405 | name: string, | 407 | name: string |
406 | fileUrl: string | 408 | fileUrl: string |
407 | } | 409 | } |
408 | attributedTo: ActivityPubAttributedTo[] | 410 | attributedTo: ActivityPubAttributedTo[] |
diff --git a/server/lib/activitypub/cache-file.ts b/server/lib/activitypub/cache-file.ts index 65b2dcb49..8252e95e9 100644 --- a/server/lib/activitypub/cache-file.ts +++ b/server/lib/activitypub/cache-file.ts | |||
@@ -13,7 +13,7 @@ function cacheFileActivityObjectToDBAttributes (cacheFileObject: CacheFileObject | |||
13 | if (!playlist) throw new Error('Cannot find HLS playlist of video ' + video.url) | 13 | if (!playlist) throw new Error('Cannot find HLS playlist of video ' + video.url) |
14 | 14 | ||
15 | return { | 15 | return { |
16 | expiresOn: new Date(cacheFileObject.expires), | 16 | expiresOn: cacheFileObject.expires ? new Date(cacheFileObject.expires) : null, |
17 | url: cacheFileObject.id, | 17 | url: cacheFileObject.id, |
18 | fileUrl: url.href, | 18 | fileUrl: url.href, |
19 | strategy: null, | 19 | strategy: null, |
@@ -30,7 +30,7 @@ function cacheFileActivityObjectToDBAttributes (cacheFileObject: CacheFileObject | |||
30 | if (!videoFile) throw new Error(`Cannot find video file ${url.height} ${url.fps} of video ${video.url}`) | 30 | if (!videoFile) throw new Error(`Cannot find video file ${url.height} ${url.fps} of video ${video.url}`) |
31 | 31 | ||
32 | return { | 32 | return { |
33 | expiresOn: new Date(cacheFileObject.expires), | 33 | expiresOn: cacheFileObject.expires ? new Date(cacheFileObject.expires) : null, |
34 | url: cacheFileObject.id, | 34 | url: cacheFileObject.id, |
35 | fileUrl: url.href, | 35 | fileUrl: url.href, |
36 | strategy: null, | 36 | strategy: null, |
diff --git a/server/lib/activitypub/crawl.ts b/server/lib/activitypub/crawl.ts index 9e469e3e6..eeafdf4ba 100644 --- a/server/lib/activitypub/crawl.ts +++ b/server/lib/activitypub/crawl.ts | |||
@@ -3,7 +3,7 @@ import { doRequest } from '../../helpers/requests' | |||
3 | import { logger } from '../../helpers/logger' | 3 | import { logger } from '../../helpers/logger' |
4 | import * as Bluebird from 'bluebird' | 4 | import * as Bluebird from 'bluebird' |
5 | import { ActivityPubOrderedCollection } from '../../../shared/models/activitypub' | 5 | import { ActivityPubOrderedCollection } from '../../../shared/models/activitypub' |
6 | import { parse } from 'url' | 6 | import { URL } from 'url' |
7 | 7 | ||
8 | type HandlerFunction<T> = (items: T[]) => (Promise<any> | Bluebird<any>) | 8 | type HandlerFunction<T> = (items: T[]) => (Promise<any> | Bluebird<any>) |
9 | type CleanerFunction = (startedDate: Date) => (Promise<any> | Bluebird<any>) | 9 | type CleanerFunction = (startedDate: Date) => (Promise<any> | Bluebird<any>) |
@@ -24,7 +24,7 @@ async function crawlCollectionPage <T> (uri: string, handler: HandlerFunction<T> | |||
24 | const response = await doRequest<ActivityPubOrderedCollection<T>>(options) | 24 | const response = await doRequest<ActivityPubOrderedCollection<T>>(options) |
25 | const firstBody = response.body | 25 | const firstBody = response.body |
26 | 26 | ||
27 | let limit = ACTIVITY_PUB.FETCH_PAGE_LIMIT | 27 | const limit = ACTIVITY_PUB.FETCH_PAGE_LIMIT |
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) { |
@@ -32,7 +32,7 @@ async function crawlCollectionPage <T> (uri: string, handler: HandlerFunction<T> | |||
32 | 32 | ||
33 | if (typeof nextLink === 'string') { | 33 | if (typeof nextLink === 'string') { |
34 | // Don't crawl ourselves | 34 | // Don't crawl ourselves |
35 | const remoteHost = parse(nextLink).host | 35 | const remoteHost = new URL(nextLink).host |
36 | if (remoteHost === WEBSERVER.HOST) continue | 36 | if (remoteHost === WEBSERVER.HOST) continue |
37 | 37 | ||
38 | options.uri = nextLink | 38 | options.uri = nextLink |
diff --git a/server/lib/activitypub/follow.ts b/server/lib/activitypub/follow.ts index 1abf43cd4..a1c95504e 100644 --- a/server/lib/activitypub/follow.ts +++ b/server/lib/activitypub/follow.ts | |||
@@ -27,7 +27,6 @@ async function autoFollowBackIfNeeded (actorFollow: MActorFollowActors) { | |||
27 | } | 27 | } |
28 | 28 | ||
29 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) | 29 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) |
30 | .catch(err => logger.error('Cannot create auto follow back job for %s.', host, err)) | ||
31 | } | 30 | } |
32 | } | 31 | } |
33 | 32 | ||
diff --git a/server/lib/activitypub/send/send-accept.ts b/server/lib/activitypub/send/send-accept.ts index 9f0225b64..c4c6b849b 100644 --- a/server/lib/activitypub/send/send-accept.ts +++ b/server/lib/activitypub/send/send-accept.ts | |||
@@ -5,7 +5,7 @@ import { buildFollowActivity } from './send-follow' | |||
5 | import { logger } from '../../../helpers/logger' | 5 | import { logger } from '../../../helpers/logger' |
6 | import { MActor, MActorFollowActors } from '../../../typings/models' | 6 | import { MActor, MActorFollowActors } from '../../../typings/models' |
7 | 7 | ||
8 | async function sendAccept (actorFollow: MActorFollowActors) { | 8 | function sendAccept (actorFollow: MActorFollowActors) { |
9 | const follower = actorFollow.ActorFollower | 9 | const follower = actorFollow.ActorFollower |
10 | const me = actorFollow.ActorFollowing | 10 | const me = actorFollow.ActorFollowing |
11 | 11 | ||
diff --git a/server/lib/activitypub/send/send-announce.ts b/server/lib/activitypub/send/send-announce.ts index a0f33852c..d03b358f1 100644 --- a/server/lib/activitypub/send/send-announce.ts +++ b/server/lib/activitypub/send/send-announce.ts | |||
@@ -28,7 +28,7 @@ async function sendVideoAnnounce (byActor: MActorLight, videoShare: MVideoShare, | |||
28 | logger.info('Creating job to send announce %s.', videoShare.url) | 28 | logger.info('Creating job to send announce %s.', videoShare.url) |
29 | 29 | ||
30 | const followersException = [ byActor ] | 30 | const followersException = [ byActor ] |
31 | return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException) | 31 | return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException, 'Announce') |
32 | } | 32 | } |
33 | 33 | ||
34 | function buildAnnounceActivity (url: string, byActor: MActorLight, object: string, audience?: ActivityAudience): ActivityAnnounce { | 34 | function buildAnnounceActivity (url: string, byActor: MActorLight, object: string, audience?: ActivityAudience): ActivityAnnounce { |
diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts index 1709d8348..3585d704a 100644 --- a/server/lib/activitypub/send/send-create.ts +++ b/server/lib/activitypub/send/send-create.ts | |||
@@ -130,10 +130,10 @@ export { | |||
130 | // --------------------------------------------------------------------------- | 130 | // --------------------------------------------------------------------------- |
131 | 131 | ||
132 | async function sendVideoRelatedCreateActivity (options: { | 132 | async function sendVideoRelatedCreateActivity (options: { |
133 | byActor: MActorLight, | 133 | byActor: MActorLight |
134 | video: MVideoAccountLight, | 134 | video: MVideoAccountLight |
135 | url: string, | 135 | url: string |
136 | object: any, | 136 | object: any |
137 | transaction?: Transaction | 137 | transaction?: Transaction |
138 | }) { | 138 | }) { |
139 | const activityBuilder = (audience: ActivityAudience) => { | 139 | const activityBuilder = (audience: ActivityAudience) => { |
diff --git a/server/lib/activitypub/send/send-dislike.ts b/server/lib/activitypub/send/send-dislike.ts index 6e41f241f..600469c71 100644 --- a/server/lib/activitypub/send/send-dislike.ts +++ b/server/lib/activitypub/send/send-dislike.ts | |||
@@ -6,7 +6,7 @@ import { sendVideoRelatedActivity } from './utils' | |||
6 | import { audiencify, getAudience } from '../audience' | 6 | import { audiencify, getAudience } from '../audience' |
7 | import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' | 7 | import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' |
8 | 8 | ||
9 | async function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { | 9 | function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { |
10 | logger.info('Creating job to dislike %s.', video.url) | 10 | logger.info('Creating job to dislike %s.', video.url) |
11 | 11 | ||
12 | const activityBuilder = (audience: ActivityAudience) => { | 12 | const activityBuilder = (audience: ActivityAudience) => { |
diff --git a/server/lib/activitypub/send/send-flag.ts b/server/lib/activitypub/send/send-flag.ts index da7638a7b..e4e523631 100644 --- a/server/lib/activitypub/send/send-flag.ts +++ b/server/lib/activitypub/send/send-flag.ts | |||
@@ -7,7 +7,7 @@ import { Transaction } from 'sequelize' | |||
7 | import { MActor, MVideoFullLight } from '../../../typings/models' | 7 | import { MActor, MVideoFullLight } from '../../../typings/models' |
8 | import { MVideoAbuseVideo } from '../../../typings/models/video' | 8 | import { MVideoAbuseVideo } from '../../../typings/models/video' |
9 | 9 | ||
10 | async function sendVideoAbuse (byActor: MActor, videoAbuse: MVideoAbuseVideo, video: MVideoFullLight, t: Transaction) { | 10 | function sendVideoAbuse (byActor: MActor, videoAbuse: MVideoAbuseVideo, video: MVideoFullLight, t: Transaction) { |
11 | if (!video.VideoChannel.Account.Actor.serverId) return // Local user | 11 | if (!video.VideoChannel.Account.Actor.serverId) return // Local user |
12 | 12 | ||
13 | const url = getVideoAbuseActivityPubUrl(videoAbuse) | 13 | const url = getVideoAbuseActivityPubUrl(videoAbuse) |
diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts index e84a6f98b..5db252325 100644 --- a/server/lib/activitypub/send/send-like.ts +++ b/server/lib/activitypub/send/send-like.ts | |||
@@ -6,7 +6,7 @@ import { audiencify, getAudience } from '../audience' | |||
6 | import { logger } from '../../../helpers/logger' | 6 | import { logger } from '../../../helpers/logger' |
7 | import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' | 7 | import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' |
8 | 8 | ||
9 | async function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { | 9 | function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { |
10 | logger.info('Creating job to like %s.', video.url) | 10 | logger.info('Creating job to like %s.', video.url) |
11 | 11 | ||
12 | const activityBuilder = (audience: ActivityAudience) => { | 12 | const activityBuilder = (audience: ActivityAudience) => { |
diff --git a/server/lib/activitypub/send/send-reject.ts b/server/lib/activitypub/send/send-reject.ts index 4258a3c36..643c468a9 100644 --- a/server/lib/activitypub/send/send-reject.ts +++ b/server/lib/activitypub/send/send-reject.ts | |||
@@ -5,7 +5,7 @@ import { buildFollowActivity } from './send-follow' | |||
5 | import { logger } from '../../../helpers/logger' | 5 | import { logger } from '../../../helpers/logger' |
6 | import { MActor } from '../../../typings/models' | 6 | import { MActor } from '../../../typings/models' |
7 | 7 | ||
8 | async function sendReject (follower: MActor, following: MActor) { | 8 | function sendReject (follower: MActor, following: MActor) { |
9 | if (!follower.serverId) { // This should never happen | 9 | if (!follower.serverId) { // This should never happen |
10 | logger.warn('Do not sending reject to local follower.') | 10 | logger.warn('Do not sending reject to local follower.') |
11 | return | 11 | return |
diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts index e9ab5b3c5..33f1d4921 100644 --- a/server/lib/activitypub/send/send-undo.ts +++ b/server/lib/activitypub/send/send-undo.ts | |||
@@ -28,7 +28,7 @@ import { | |||
28 | MVideoShare | 28 | MVideoShare |
29 | } from '../../../typings/models' | 29 | } from '../../../typings/models' |
30 | 30 | ||
31 | async function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) { | 31 | function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) { |
32 | const me = actorFollow.ActorFollower | 32 | const me = actorFollow.ActorFollower |
33 | const following = actorFollow.ActorFollowing | 33 | const following = actorFollow.ActorFollowing |
34 | 34 | ||
@@ -118,10 +118,10 @@ function undoActivityData ( | |||
118 | } | 118 | } |
119 | 119 | ||
120 | async function sendUndoVideoRelatedActivity (options: { | 120 | async function sendUndoVideoRelatedActivity (options: { |
121 | byActor: MActor, | 121 | byActor: MActor |
122 | video: MVideoAccountLight, | 122 | video: MVideoAccountLight |
123 | url: string, | 123 | url: string |
124 | activity: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce, | 124 | activity: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce |
125 | transaction: Transaction | 125 | transaction: Transaction |
126 | }) { | 126 | }) { |
127 | const activityBuilder = (audience: ActivityAudience) => { | 127 | const activityBuilder = (audience: ActivityAudience) => { |
diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts index 9c76671b5..cb500bd34 100644 --- a/server/lib/activitypub/send/send-update.ts +++ b/server/lib/activitypub/send/send-update.ts | |||
@@ -8,7 +8,6 @@ import { getUpdateActivityPubUrl } from '../url' | |||
8 | import { broadcastToFollowers, sendVideoRelatedActivity } from './utils' | 8 | import { broadcastToFollowers, sendVideoRelatedActivity } from './utils' |
9 | import { audiencify, getActorsInvolvedInVideo, getAudience } from '../audience' | 9 | import { audiencify, getActorsInvolvedInVideo, getAudience } from '../audience' |
10 | import { logger } from '../../../helpers/logger' | 10 | import { logger } from '../../../helpers/logger' |
11 | import { VideoCaptionModel } from '../../../models/video/video-caption' | ||
12 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' | 11 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' |
13 | import { getServerActor } from '../../../helpers/utils' | 12 | import { getServerActor } from '../../../helpers/utils' |
14 | import { | 13 | import { |
@@ -29,7 +28,7 @@ async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, t: Transaction | |||
29 | 28 | ||
30 | logger.info('Creating job to update video %s.', video.url) | 29 | logger.info('Creating job to update video %s.', video.url) |
31 | 30 | ||
32 | const byActor = overrodeByActor ? overrodeByActor : video.VideoChannel.Account.Actor | 31 | const byActor = overrodeByActor || video.VideoChannel.Account.Actor |
33 | 32 | ||
34 | const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString()) | 33 | const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString()) |
35 | 34 | ||
diff --git a/server/lib/activitypub/send/send-view.ts b/server/lib/activitypub/send/send-view.ts index 8809417f9..47482b9a9 100644 --- a/server/lib/activitypub/send/send-view.ts +++ b/server/lib/activitypub/send/send-view.ts | |||
@@ -16,7 +16,7 @@ async function sendView (byActor: ActorModel, video: MVideoAccountLight, t: Tran | |||
16 | return buildViewActivity(url, byActor, video, audience) | 16 | return buildViewActivity(url, byActor, video, audience) |
17 | } | 17 | } |
18 | 18 | ||
19 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t }) | 19 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t, contextType: 'View' }) |
20 | } | 20 | } |
21 | 21 | ||
22 | function buildViewActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityView { | 22 | function buildViewActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityView { |
diff --git a/server/lib/activitypub/send/utils.ts b/server/lib/activitypub/send/utils.ts index 77b723479..0d67bb3d6 100644 --- a/server/lib/activitypub/send/utils.ts +++ b/server/lib/activitypub/send/utils.ts | |||
@@ -8,13 +8,15 @@ import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAud | |||
8 | import { getServerActor } from '../../../helpers/utils' | 8 | import { getServerActor } from '../../../helpers/utils' |
9 | import { afterCommitIfTransaction } from '../../../helpers/database-utils' | 9 | import { afterCommitIfTransaction } from '../../../helpers/database-utils' |
10 | import { MActorWithInboxes, MActor, MActorId, MActorLight, MVideo, MVideoAccountLight } from '../../../typings/models' | 10 | import { MActorWithInboxes, MActor, MActorId, MActorLight, MVideo, MVideoAccountLight } from '../../../typings/models' |
11 | import { ContextType } from '@server/helpers/activitypub' | ||
11 | 12 | ||
12 | async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { | 13 | async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { |
13 | byActor: MActorLight, | 14 | byActor: MActorLight |
14 | video: MVideoAccountLight, | 15 | video: MVideoAccountLight |
15 | transaction?: Transaction | 16 | transaction?: Transaction |
17 | contextType?: ContextType | ||
16 | }) { | 18 | }) { |
17 | const { byActor, video, transaction } = options | 19 | const { byActor, video, transaction, contextType } = options |
18 | 20 | ||
19 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction) | 21 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction) |
20 | 22 | ||
@@ -24,7 +26,7 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud | |||
24 | const activity = activityBuilder(audience) | 26 | const activity = activityBuilder(audience) |
25 | 27 | ||
26 | return afterCommitIfTransaction(transaction, () => { | 28 | return afterCommitIfTransaction(transaction, () => { |
27 | return unicastTo(activity, byActor, video.VideoChannel.Account.Actor.getSharedInbox()) | 29 | return unicastTo(activity, byActor, video.VideoChannel.Account.Actor.getSharedInbox(), contextType) |
28 | }) | 30 | }) |
29 | } | 31 | } |
30 | 32 | ||
@@ -34,7 +36,7 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud | |||
34 | 36 | ||
35 | const actorsException = [ byActor ] | 37 | const actorsException = [ byActor ] |
36 | 38 | ||
37 | return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException) | 39 | return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException, contextType) |
38 | } | 40 | } |
39 | 41 | ||
40 | async function forwardVideoRelatedActivity ( | 42 | async function forwardVideoRelatedActivity ( |
@@ -90,11 +92,12 @@ async function broadcastToFollowers ( | |||
90 | byActor: MActorId, | 92 | byActor: MActorId, |
91 | toFollowersOf: MActorId[], | 93 | toFollowersOf: MActorId[], |
92 | t: Transaction, | 94 | t: Transaction, |
93 | actorsException: MActorWithInboxes[] = [] | 95 | actorsException: MActorWithInboxes[] = [], |
96 | contextType?: ContextType | ||
94 | ) { | 97 | ) { |
95 | const uris = await computeFollowerUris(toFollowersOf, actorsException, t) | 98 | const uris = await computeFollowerUris(toFollowersOf, actorsException, t) |
96 | 99 | ||
97 | return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor)) | 100 | return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType)) |
98 | } | 101 | } |
99 | 102 | ||
100 | async function broadcastToActors ( | 103 | async function broadcastToActors ( |
@@ -102,13 +105,14 @@ async function broadcastToActors ( | |||
102 | byActor: MActorId, | 105 | byActor: MActorId, |
103 | toActors: MActor[], | 106 | toActors: MActor[], |
104 | t?: Transaction, | 107 | t?: Transaction, |
105 | actorsException: MActorWithInboxes[] = [] | 108 | actorsException: MActorWithInboxes[] = [], |
109 | contextType?: ContextType | ||
106 | ) { | 110 | ) { |
107 | const uris = await computeUris(toActors, actorsException) | 111 | const uris = await computeUris(toActors, actorsException) |
108 | return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor)) | 112 | return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType)) |
109 | } | 113 | } |
110 | 114 | ||
111 | function broadcastTo (uris: string[], data: any, byActor: MActorId) { | 115 | function broadcastTo (uris: string[], data: any, byActor: MActorId, contextType?: ContextType) { |
112 | if (uris.length === 0) return undefined | 116 | if (uris.length === 0) return undefined |
113 | 117 | ||
114 | logger.debug('Creating broadcast job.', { uris }) | 118 | logger.debug('Creating broadcast job.', { uris }) |
@@ -116,19 +120,21 @@ function broadcastTo (uris: string[], data: any, byActor: MActorId) { | |||
116 | const payload = { | 120 | const payload = { |
117 | uris, | 121 | uris, |
118 | signatureActorId: byActor.id, | 122 | signatureActorId: byActor.id, |
119 | body: data | 123 | body: data, |
124 | contextType | ||
120 | } | 125 | } |
121 | 126 | ||
122 | return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }) | 127 | return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }) |
123 | } | 128 | } |
124 | 129 | ||
125 | function unicastTo (data: any, byActor: MActorId, toActorUrl: string) { | 130 | function unicastTo (data: any, byActor: MActorId, toActorUrl: string, contextType?: ContextType) { |
126 | logger.debug('Creating unicast job.', { uri: toActorUrl }) | 131 | logger.debug('Creating unicast job.', { uri: toActorUrl }) |
127 | 132 | ||
128 | const payload = { | 133 | const payload = { |
129 | uri: toActorUrl, | 134 | uri: toActorUrl, |
130 | signatureActorId: byActor.id, | 135 | signatureActorId: byActor.id, |
131 | body: data | 136 | body: data, |
137 | contextType | ||
132 | } | 138 | } |
133 | 139 | ||
134 | JobQueue.Instance.createJob({ type: 'activitypub-http-unicast', payload }) | 140 | JobQueue.Instance.createJob({ type: 'activitypub-http-unicast', payload }) |
diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts index d5c078a29..8642d2432 100644 --- a/server/lib/activitypub/video-comments.ts +++ b/server/lib/activitypub/video-comments.ts | |||
@@ -10,9 +10,9 @@ import { checkUrlsSameHost } from '../../helpers/activitypub' | |||
10 | import { MCommentOwner, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../typings/models/video' | 10 | import { MCommentOwner, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../typings/models/video' |
11 | 11 | ||
12 | type ResolveThreadParams = { | 12 | type ResolveThreadParams = { |
13 | url: string, | 13 | url: string |
14 | comments?: MCommentOwner[], | 14 | comments?: MCommentOwner[] |
15 | isVideo?: boolean, | 15 | isVideo?: boolean |
16 | commentCreated?: boolean | 16 | commentCreated?: boolean |
17 | } | 17 | } |
18 | type ResolveThreadResult = Promise<{ video: MVideoAccountLightBlacklistAllFiles, comment: MCommentOwnerVideo, commentCreated: boolean }> | 18 | type ResolveThreadResult = Promise<{ video: MVideoAccountLightBlacklistAllFiles, comment: MCommentOwnerVideo, commentCreated: boolean }> |
@@ -28,7 +28,7 @@ async function resolveThread (params: ResolveThreadParams): ResolveThreadResult | |||
28 | if (params.commentCreated === undefined) params.commentCreated = false | 28 | if (params.commentCreated === undefined) params.commentCreated = false |
29 | if (params.comments === undefined) params.comments = [] | 29 | if (params.comments === undefined) params.comments = [] |
30 | 30 | ||
31 | // Already have this comment? | 31 | // Already have this comment? |
32 | if (isVideo !== true) { | 32 | if (isVideo !== true) { |
33 | const result = await resolveCommentFromDB(params) | 33 | const result = await resolveCommentFromDB(params) |
34 | if (result) return result | 34 | if (result) return result |
@@ -87,7 +87,7 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) { | |||
87 | 87 | ||
88 | let resultComment: MCommentOwnerVideo | 88 | let resultComment: MCommentOwnerVideo |
89 | if (comments.length !== 0) { | 89 | if (comments.length !== 0) { |
90 | const firstReply = comments[ comments.length - 1 ] as MCommentOwnerVideo | 90 | const firstReply = comments[comments.length - 1] as MCommentOwnerVideo |
91 | firstReply.inReplyToCommentId = null | 91 | firstReply.inReplyToCommentId = null |
92 | firstReply.originCommentId = null | 92 | firstReply.originCommentId = null |
93 | firstReply.videoId = video.id | 93 | firstReply.videoId = video.id |
@@ -97,9 +97,9 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) { | |||
97 | comments[comments.length - 1] = await firstReply.save() | 97 | comments[comments.length - 1] = await firstReply.save() |
98 | 98 | ||
99 | for (let i = comments.length - 2; i >= 0; i--) { | 99 | for (let i = comments.length - 2; i >= 0; i--) { |
100 | const comment = comments[ i ] as MCommentOwnerVideo | 100 | const comment = comments[i] as MCommentOwnerVideo |
101 | comment.originCommentId = firstReply.id | 101 | comment.originCommentId = firstReply.id |
102 | comment.inReplyToCommentId = comments[ i + 1 ].id | 102 | comment.inReplyToCommentId = comments[i + 1].id |
103 | comment.videoId = video.id | 103 | comment.videoId = video.id |
104 | comment.changed('updatedAt', true) | 104 | comment.changed('updatedAt', true) |
105 | comment.Video = video | 105 | comment.Video = video |
diff --git a/server/lib/activitypub/video-rates.ts b/server/lib/activitypub/video-rates.ts index 6bd46bb58..79ccfbc7e 100644 --- a/server/lib/activitypub/video-rates.ts +++ b/server/lib/activitypub/video-rates.ts | |||
@@ -58,8 +58,6 @@ async function createRates (ratesUrl: string[], video: MVideo, rate: VideoRateTy | |||
58 | const field = rate === 'like' ? 'likes' : 'dislikes' | 58 | const field = rate === 'like' ? 'likes' : 'dislikes' |
59 | await video.increment(field, { by: rateCounts }) | 59 | await video.increment(field, { by: rateCounts }) |
60 | } | 60 | } |
61 | |||
62 | return | ||
63 | } | 61 | } |
64 | 62 | ||
65 | async function sendVideoRateChange ( | 63 | async function sendVideoRateChange ( |
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index ade93150f..9e43caa20 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts | |||
@@ -6,7 +6,8 @@ import { | |||
6 | ActivityHashTagObject, | 6 | ActivityHashTagObject, |
7 | ActivityMagnetUrlObject, | 7 | ActivityMagnetUrlObject, |
8 | ActivityPlaylistSegmentHashesObject, | 8 | ActivityPlaylistSegmentHashesObject, |
9 | ActivityPlaylistUrlObject, ActivityTagObject, | 9 | ActivityPlaylistUrlObject, |
10 | ActivityTagObject, | ||
10 | ActivityUrlObject, | 11 | ActivityUrlObject, |
11 | ActivityVideoUrlObject, | 12 | ActivityVideoUrlObject, |
12 | VideoState | 13 | VideoState |
@@ -17,14 +18,14 @@ import { sanitizeAndCheckVideoTorrentObject } from '../../helpers/custom-validat | |||
17 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' | 18 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' |
18 | import { deleteNonExistingModels, resetSequelizeInstance, retryTransactionWrapper } from '../../helpers/database-utils' | 19 | import { deleteNonExistingModels, resetSequelizeInstance, retryTransactionWrapper } from '../../helpers/database-utils' |
19 | import { logger } from '../../helpers/logger' | 20 | import { logger } from '../../helpers/logger' |
20 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' | 21 | import { doRequest } from '../../helpers/requests' |
21 | import { | 22 | import { |
22 | ACTIVITY_PUB, | 23 | ACTIVITY_PUB, |
23 | MIMETYPES, | 24 | MIMETYPES, |
24 | P2P_MEDIA_LOADER_PEER_VERSION, | 25 | P2P_MEDIA_LOADER_PEER_VERSION, |
25 | PREVIEWS_SIZE, | 26 | PREVIEWS_SIZE, |
26 | REMOTE_SCHEME, | 27 | REMOTE_SCHEME, |
27 | STATIC_PATHS | 28 | STATIC_PATHS, THUMBNAILS_SIZE |
28 | } from '../../initializers/constants' | 29 | } from '../../initializers/constants' |
29 | import { TagModel } from '../../models/video/tag' | 30 | import { TagModel } from '../../models/video/tag' |
30 | import { VideoModel } from '../../models/video/video' | 31 | import { VideoModel } from '../../models/video/video' |
@@ -40,7 +41,7 @@ import { ActivitypubHttpFetcherPayload } from '../job-queue/handlers/activitypub | |||
40 | import { createRates } from './video-rates' | 41 | import { createRates } from './video-rates' |
41 | import { addVideoShares, shareVideoByServerAndChannel } from './share' | 42 | import { addVideoShares, shareVideoByServerAndChannel } from './share' |
42 | import { fetchVideoByUrl, VideoFetchByUrlType } from '../../helpers/video' | 43 | import { fetchVideoByUrl, VideoFetchByUrlType } from '../../helpers/video' |
43 | import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' | 44 | import { buildRemoteVideoBaseUrl, checkUrlsSameHost, getAPId } from '../../helpers/activitypub' |
44 | import { Notifier } from '../notifier' | 45 | import { Notifier } from '../notifier' |
45 | import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist' | 46 | import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist' |
46 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' | 47 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' |
@@ -71,6 +72,7 @@ import { | |||
71 | MVideoThumbnail | 72 | MVideoThumbnail |
72 | } from '../../typings/models' | 73 | } from '../../typings/models' |
73 | import { MThumbnail } from '../../typings/models/video/thumbnail' | 74 | import { MThumbnail } from '../../typings/models/video/thumbnail' |
75 | import { maxBy, minBy } from 'lodash' | ||
74 | 76 | ||
75 | async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) { | 77 | async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) { |
76 | const video = videoArg as MVideoAP | 78 | const video = videoArg as MVideoAP |
@@ -131,19 +133,6 @@ async function fetchRemoteVideoDescription (video: MVideoAccountLight) { | |||
131 | return body.description ? body.description : '' | 133 | return body.description ? body.description : '' |
132 | } | 134 | } |
133 | 135 | ||
134 | function fetchRemoteVideoStaticFile (video: MVideoAccountLight, path: string, destPath: string) { | ||
135 | const url = buildRemoteBaseUrl(video, path) | ||
136 | |||
137 | // We need to provide a callback, if no we could have an uncaught exception | ||
138 | return doRequestAndSaveToFile({ uri: url }, destPath) | ||
139 | } | ||
140 | |||
141 | function buildRemoteBaseUrl (video: MVideoAccountLight, path: string) { | ||
142 | const host = video.VideoChannel.Account.Actor.Server.host | ||
143 | |||
144 | return REMOTE_SCHEME.HTTP + '://' + host + path | ||
145 | } | ||
146 | |||
147 | function getOrCreateVideoChannelFromVideoObject (videoObject: VideoTorrentObject) { | 136 | function getOrCreateVideoChannelFromVideoObject (videoObject: VideoTorrentObject) { |
148 | const channel = videoObject.attributedTo.find(a => a.type === 'Group') | 137 | const channel = videoObject.attributedTo.find(a => a.type === 'Group') |
149 | if (!channel) throw new Error('Cannot find associated video channel to video ' + videoObject.url) | 138 | if (!channel) throw new Error('Cannot find associated video channel to video ' + videoObject.url) |
@@ -173,7 +162,7 @@ async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTo | |||
173 | const cleaner = crawlStartDate => AccountVideoRateModel.cleanOldRatesOf(video.id, 'like' as 'like', crawlStartDate) | 162 | const cleaner = crawlStartDate => AccountVideoRateModel.cleanOldRatesOf(video.id, 'like' as 'like', crawlStartDate) |
174 | 163 | ||
175 | await crawlCollectionPage<string>(fetchedVideo.likes, handler, cleaner) | 164 | await crawlCollectionPage<string>(fetchedVideo.likes, handler, cleaner) |
176 | .catch(err => logger.error('Cannot add likes of video %s.', video.uuid, { err })) | 165 | .catch(err => logger.error('Cannot add likes of video %s.', video.uuid, { err, rootUrl: fetchedVideo.likes })) |
177 | } else { | 166 | } else { |
178 | jobPayloads.push({ uri: fetchedVideo.likes, videoId: video.id, type: 'video-likes' as 'video-likes' }) | 167 | jobPayloads.push({ uri: fetchedVideo.likes, videoId: video.id, type: 'video-likes' as 'video-likes' }) |
179 | } | 168 | } |
@@ -183,7 +172,7 @@ async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTo | |||
183 | const cleaner = crawlStartDate => AccountVideoRateModel.cleanOldRatesOf(video.id, 'dislike' as 'dislike', crawlStartDate) | 172 | const cleaner = crawlStartDate => AccountVideoRateModel.cleanOldRatesOf(video.id, 'dislike' as 'dislike', crawlStartDate) |
184 | 173 | ||
185 | await crawlCollectionPage<string>(fetchedVideo.dislikes, handler, cleaner) | 174 | await crawlCollectionPage<string>(fetchedVideo.dislikes, handler, cleaner) |
186 | .catch(err => logger.error('Cannot add dislikes of video %s.', video.uuid, { err })) | 175 | .catch(err => logger.error('Cannot add dislikes of video %s.', video.uuid, { err, rootUrl: fetchedVideo.dislikes })) |
187 | } else { | 176 | } else { |
188 | jobPayloads.push({ uri: fetchedVideo.dislikes, videoId: video.id, type: 'video-dislikes' as 'video-dislikes' }) | 177 | jobPayloads.push({ uri: fetchedVideo.dislikes, videoId: video.id, type: 'video-dislikes' as 'video-dislikes' }) |
189 | } | 178 | } |
@@ -193,7 +182,7 @@ async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTo | |||
193 | const cleaner = crawlStartDate => VideoShareModel.cleanOldSharesOf(video.id, crawlStartDate) | 182 | const cleaner = crawlStartDate => VideoShareModel.cleanOldSharesOf(video.id, crawlStartDate) |
194 | 183 | ||
195 | await crawlCollectionPage<string>(fetchedVideo.shares, handler, cleaner) | 184 | await crawlCollectionPage<string>(fetchedVideo.shares, handler, cleaner) |
196 | .catch(err => logger.error('Cannot add shares of video %s.', video.uuid, { err })) | 185 | .catch(err => logger.error('Cannot add shares of video %s.', video.uuid, { err, rootUrl: fetchedVideo.shares })) |
197 | } else { | 186 | } else { |
198 | jobPayloads.push({ uri: fetchedVideo.shares, videoId: video.id, type: 'video-shares' as 'video-shares' }) | 187 | jobPayloads.push({ uri: fetchedVideo.shares, videoId: video.id, type: 'video-shares' as 'video-shares' }) |
199 | } | 188 | } |
@@ -203,30 +192,30 @@ async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTo | |||
203 | const cleaner = crawlStartDate => VideoCommentModel.cleanOldCommentsOf(video.id, crawlStartDate) | 192 | const cleaner = crawlStartDate => VideoCommentModel.cleanOldCommentsOf(video.id, crawlStartDate) |
204 | 193 | ||
205 | await crawlCollectionPage<string>(fetchedVideo.comments, handler, cleaner) | 194 | await crawlCollectionPage<string>(fetchedVideo.comments, handler, cleaner) |
206 | .catch(err => logger.error('Cannot add comments of video %s.', video.uuid, { err })) | 195 | .catch(err => logger.error('Cannot add comments of video %s.', video.uuid, { err, rootUrl: fetchedVideo.comments })) |
207 | } else { | 196 | } else { |
208 | jobPayloads.push({ uri: fetchedVideo.comments, videoId: video.id, type: 'video-comments' as 'video-comments' }) | 197 | jobPayloads.push({ uri: fetchedVideo.comments, videoId: video.id, type: 'video-comments' as 'video-comments' }) |
209 | } | 198 | } |
210 | 199 | ||
211 | await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })) | 200 | await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload })) |
212 | } | 201 | } |
213 | 202 | ||
214 | function getOrCreateVideoAndAccountAndChannel (options: { | 203 | function getOrCreateVideoAndAccountAndChannel (options: { |
215 | videoObject: { id: string } | string, | 204 | videoObject: { id: string } | string |
216 | syncParam?: SyncParam, | 205 | syncParam?: SyncParam |
217 | fetchType?: 'all', | 206 | fetchType?: 'all' |
218 | allowRefresh?: boolean | 207 | allowRefresh?: boolean |
219 | }): Promise<{ video: MVideoAccountLightBlacklistAllFiles, created: boolean, autoBlacklisted?: boolean }> | 208 | }): Promise<{ video: MVideoAccountLightBlacklistAllFiles, created: boolean, autoBlacklisted?: boolean }> |
220 | function getOrCreateVideoAndAccountAndChannel (options: { | 209 | function getOrCreateVideoAndAccountAndChannel (options: { |
221 | videoObject: { id: string } | string, | 210 | videoObject: { id: string } | string |
222 | syncParam?: SyncParam, | 211 | syncParam?: SyncParam |
223 | fetchType?: VideoFetchByUrlType, | 212 | fetchType?: VideoFetchByUrlType |
224 | allowRefresh?: boolean | 213 | allowRefresh?: boolean |
225 | }): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> | 214 | }): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> |
226 | async function getOrCreateVideoAndAccountAndChannel (options: { | 215 | async function getOrCreateVideoAndAccountAndChannel (options: { |
227 | videoObject: { id: string } | string, | 216 | videoObject: { id: string } | string |
228 | syncParam?: SyncParam, | 217 | syncParam?: SyncParam |
229 | fetchType?: VideoFetchByUrlType, | 218 | fetchType?: VideoFetchByUrlType |
230 | allowRefresh?: boolean // true by default | 219 | allowRefresh?: boolean // true by default |
231 | }): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> { | 220 | }): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> { |
232 | // Default params | 221 | // Default params |
@@ -246,8 +235,14 @@ async function getOrCreateVideoAndAccountAndChannel (options: { | |||
246 | syncParam | 235 | syncParam |
247 | } | 236 | } |
248 | 237 | ||
249 | if (syncParam.refreshVideo === true) videoFromDatabase = await refreshVideoIfNeeded(refreshOptions) | 238 | if (syncParam.refreshVideo === true) { |
250 | else await JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: videoFromDatabase.url } }) | 239 | videoFromDatabase = await refreshVideoIfNeeded(refreshOptions) |
240 | } else { | ||
241 | await JobQueue.Instance.createJobWithPromise({ | ||
242 | type: 'activitypub-refresher', | ||
243 | payload: { type: 'video', url: videoFromDatabase.url } | ||
244 | }) | ||
245 | } | ||
251 | } | 246 | } |
252 | 247 | ||
253 | return { video: videoFromDatabase, created: false } | 248 | return { video: videoFromDatabase, created: false } |
@@ -266,10 +261,10 @@ async function getOrCreateVideoAndAccountAndChannel (options: { | |||
266 | } | 261 | } |
267 | 262 | ||
268 | async function updateVideoFromAP (options: { | 263 | async function updateVideoFromAP (options: { |
269 | video: MVideoAccountLightBlacklistAllFiles, | 264 | video: MVideoAccountLightBlacklistAllFiles |
270 | videoObject: VideoTorrentObject, | 265 | videoObject: VideoTorrentObject |
271 | account: MAccountIdActor, | 266 | account: MAccountIdActor |
272 | channel: MChannelDefault, | 267 | channel: MChannelDefault |
273 | overrideTo?: string[] | 268 | overrideTo?: string[] |
274 | }) { | 269 | }) { |
275 | const { video, videoObject, account, channel, overrideTo } = options | 270 | const { video, videoObject, account, channel, overrideTo } = options |
@@ -284,7 +279,7 @@ async function updateVideoFromAP (options: { | |||
284 | let thumbnailModel: MThumbnail | 279 | let thumbnailModel: MThumbnail |
285 | 280 | ||
286 | try { | 281 | try { |
287 | thumbnailModel = await createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE) | 282 | thumbnailModel = await createVideoMiniatureFromUrl(getThumbnailFromIcons(videoObject).url, video, ThumbnailType.MINIATURE) |
288 | } catch (err) { | 283 | } catch (err) { |
289 | logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err }) | 284 | logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err }) |
290 | } | 285 | } |
@@ -300,7 +295,7 @@ async function updateVideoFromAP (options: { | |||
300 | throw new Error('Account ' + account.Actor.url + ' does not own video channel ' + videoChannel.Actor.url) | 295 | throw new Error('Account ' + account.Actor.url + ' does not own video channel ' + videoChannel.Actor.url) |
301 | } | 296 | } |
302 | 297 | ||
303 | const to = overrideTo ? overrideTo : videoObject.to | 298 | const to = overrideTo || videoObject.to |
304 | const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, to) | 299 | const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, to) |
305 | video.name = videoData.name | 300 | video.name = videoData.name |
306 | video.uuid = videoData.uuid | 301 | video.uuid = videoData.uuid |
@@ -327,8 +322,7 @@ async function updateVideoFromAP (options: { | |||
327 | 322 | ||
328 | if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t) | 323 | if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t) |
329 | 324 | ||
330 | // FIXME: use icon URL instead | 325 | const previewUrl = videoUpdated.getPreview().getFileUrl(videoUpdated) |
331 | const previewUrl = buildRemoteBaseUrl(videoUpdated, join(STATIC_PATHS.PREVIEWS, videoUpdated.getPreview().filename)) | ||
332 | const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) | 326 | const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) |
333 | await videoUpdated.addAndSaveThumbnail(previewModel, t) | 327 | await videoUpdated.addAndSaveThumbnail(previewModel, t) |
334 | 328 | ||
@@ -391,7 +385,7 @@ async function updateVideoFromAP (options: { | |||
391 | await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(videoUpdated.id, t) | 385 | await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(videoUpdated.id, t) |
392 | 386 | ||
393 | const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { | 387 | const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { |
394 | return VideoCaptionModel.insertOrReplaceLanguage(videoUpdated.id, c.identifier, t) | 388 | return VideoCaptionModel.insertOrReplaceLanguage(videoUpdated.id, c.identifier, c.url, t) |
395 | }) | 389 | }) |
396 | await Promise.all(videoCaptionsPromises) | 390 | await Promise.all(videoCaptionsPromises) |
397 | } | 391 | } |
@@ -424,8 +418,8 @@ async function updateVideoFromAP (options: { | |||
424 | } | 418 | } |
425 | 419 | ||
426 | async function refreshVideoIfNeeded (options: { | 420 | async function refreshVideoIfNeeded (options: { |
427 | video: MVideoThumbnail, | 421 | video: MVideoThumbnail |
428 | fetchedType: VideoFetchByUrlType, | 422 | fetchedType: VideoFetchByUrlType |
429 | syncParam: SyncParam | 423 | syncParam: SyncParam |
430 | }): Promise<MVideoThumbnail> { | 424 | }): Promise<MVideoThumbnail> { |
431 | if (!options.video.isOutdated()) return options.video | 425 | if (!options.video.isOutdated()) return options.video |
@@ -483,7 +477,6 @@ export { | |||
483 | federateVideoIfNeeded, | 477 | federateVideoIfNeeded, |
484 | fetchRemoteVideo, | 478 | fetchRemoteVideo, |
485 | getOrCreateVideoAndAccountAndChannel, | 479 | getOrCreateVideoAndAccountAndChannel, |
486 | fetchRemoteVideoStaticFile, | ||
487 | fetchRemoteVideoDescription, | 480 | fetchRemoteVideoDescription, |
488 | getOrCreateVideoChannelFromVideoObject | 481 | getOrCreateVideoChannelFromVideoObject |
489 | } | 482 | } |
@@ -519,7 +512,7 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc | |||
519 | const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, videoObject.to) | 512 | const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, videoObject.to) |
520 | const video = VideoModel.build(videoData) as MVideoThumbnail | 513 | const video = VideoModel.build(videoData) as MVideoThumbnail |
521 | 514 | ||
522 | const promiseThumbnail = createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE) | 515 | const promiseThumbnail = createVideoMiniatureFromUrl(getThumbnailFromIcons(videoObject).url, video, ThumbnailType.MINIATURE) |
523 | 516 | ||
524 | let thumbnailModel: MThumbnail | 517 | let thumbnailModel: MThumbnail |
525 | if (waitThumbnail === true) { | 518 | if (waitThumbnail === true) { |
@@ -534,9 +527,12 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc | |||
534 | 527 | ||
535 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) | 528 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) |
536 | 529 | ||
537 | // FIXME: use icon URL instead | 530 | const previewIcon = getPreviewFromIcons(videoObject) |
538 | const previewUrl = buildRemoteBaseUrl(videoCreated, join(STATIC_PATHS.PREVIEWS, video.generatePreviewName())) | 531 | const previewUrl = previewIcon |
539 | const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) | 532 | ? previewIcon.url |
533 | : buildRemoteVideoBaseUrl(videoCreated, join(STATIC_PATHS.PREVIEWS, video.generatePreviewName())) | ||
534 | const previewModel = createPlaceholderThumbnail(previewUrl, videoCreated, ThumbnailType.PREVIEW, PREVIEWS_SIZE) | ||
535 | |||
540 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(previewModel, t) | 536 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(previewModel, t) |
541 | 537 | ||
542 | // Process files | 538 | // Process files |
@@ -567,7 +563,7 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc | |||
567 | 563 | ||
568 | // Process captions | 564 | // Process captions |
569 | const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { | 565 | const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { |
570 | return VideoCaptionModel.insertOrReplaceLanguage(videoCreated.id, c.identifier, t) | 566 | return VideoCaptionModel.insertOrReplaceLanguage(videoCreated.id, c.identifier, c.url, t) |
571 | }) | 567 | }) |
572 | await Promise.all(videoCaptionsPromises) | 568 | await Promise.all(videoCaptionsPromises) |
573 | 569 | ||
@@ -592,13 +588,13 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc | |||
592 | thumbnailModel = videoCreated.id | 588 | thumbnailModel = videoCreated.id |
593 | 589 | ||
594 | return thumbnailModel.save() | 590 | return thumbnailModel.save() |
595 | }) | 591 | }).catch(err => logger.error('Cannot create miniature from url.', { err })) |
596 | } | 592 | } |
597 | 593 | ||
598 | return { autoBlacklisted, videoCreated } | 594 | return { autoBlacklisted, videoCreated } |
599 | } | 595 | } |
600 | 596 | ||
601 | async function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) { | 597 | function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) { |
602 | const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED | 598 | const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED |
603 | const duration = videoObject.duration.replace(/[^\d]+/, '') | 599 | const duration = videoObject.duration.replace(/[^\d]+/, '') |
604 | 600 | ||
@@ -639,7 +635,6 @@ async function videoActivityObjectToDBAttributes (videoChannel: MChannelId, vide | |||
639 | createdAt: new Date(videoObject.published), | 635 | createdAt: new Date(videoObject.published), |
640 | publishedAt: new Date(videoObject.published), | 636 | publishedAt: new Date(videoObject.published), |
641 | originallyPublishedAt: videoObject.originallyPublishedAt ? new Date(videoObject.originallyPublishedAt) : null, | 637 | originallyPublishedAt: videoObject.originallyPublishedAt ? new Date(videoObject.originallyPublishedAt) : null, |
642 | // FIXME: updatedAt does not seems to be considered by Sequelize | ||
643 | updatedAt: new Date(videoObject.updated), | 638 | updatedAt: new Date(videoObject.updated), |
644 | views: videoObject.views, | 639 | views: videoObject.views, |
645 | likes: 0, | 640 | likes: 0, |
@@ -672,7 +667,7 @@ function videoFileActivityUrlToDBAttributes ( | |||
672 | 667 | ||
673 | const mediaType = fileUrl.mediaType | 668 | const mediaType = fileUrl.mediaType |
674 | const attribute = { | 669 | const attribute = { |
675 | extname: MIMETYPES.VIDEO.MIMETYPE_EXT[ mediaType ], | 670 | extname: MIMETYPES.VIDEO.MIMETYPE_EXT[mediaType], |
676 | infoHash: parsed.infoHash, | 671 | infoHash: parsed.infoHash, |
677 | resolution: fileUrl.height, | 672 | resolution: fileUrl.height, |
678 | size: fileUrl.size, | 673 | size: fileUrl.size, |
@@ -722,3 +717,19 @@ function streamingPlaylistActivityUrlToDBAttributes (video: MVideoId, videoObjec | |||
722 | 717 | ||
723 | return attributes | 718 | return attributes |
724 | } | 719 | } |
720 | |||
721 | function getThumbnailFromIcons (videoObject: VideoTorrentObject) { | ||
722 | let validIcons = videoObject.icon.filter(i => i.width > THUMBNAILS_SIZE.minWidth) | ||
723 | // Fallback if there are not valid icons | ||
724 | if (validIcons.length === 0) validIcons = videoObject.icon | ||
725 | |||
726 | return minBy(validIcons, 'width') | ||
727 | } | ||
728 | |||
729 | function getPreviewFromIcons (videoObject: VideoTorrentObject) { | ||
730 | const validIcons = videoObject.icon.filter(i => i.width > PREVIEWS_SIZE.minWidth) | ||
731 | |||
732 | // FIXME: don't put a fallback here for compatibility with PeerTube <2.2 | ||
733 | |||
734 | return maxBy(validIcons, 'width') | ||
735 | } | ||
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts index 1d8a08ed0..572bd03bd 100644 --- a/server/lib/client-html.ts +++ b/server/lib/client-html.ts | |||
@@ -17,7 +17,7 @@ import { MAccountActor, MChannelActor, MVideo } from '../typings/models' | |||
17 | 17 | ||
18 | export class ClientHtml { | 18 | export class ClientHtml { |
19 | 19 | ||
20 | private static htmlCache: { [ path: string ]: string } = {} | 20 | private static htmlCache: { [path: string]: string } = {} |
21 | 21 | ||
22 | static invalidCache () { | 22 | static invalidCache () { |
23 | logger.info('Cleaning HTML cache.') | 23 | logger.info('Cleaning HTML cache.') |
@@ -94,7 +94,7 @@ export class ClientHtml { | |||
94 | 94 | ||
95 | private static async getIndexHTML (req: express.Request, res: express.Response, paramLang?: string) { | 95 | private static async getIndexHTML (req: express.Request, res: express.Response, paramLang?: string) { |
96 | const path = ClientHtml.getIndexPath(req, res, paramLang) | 96 | const path = ClientHtml.getIndexPath(req, res, paramLang) |
97 | if (ClientHtml.htmlCache[ path ]) return ClientHtml.htmlCache[ path ] | 97 | if (ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path] |
98 | 98 | ||
99 | const buffer = await readFile(path) | 99 | const buffer = await readFile(path) |
100 | 100 | ||
@@ -104,7 +104,7 @@ export class ClientHtml { | |||
104 | html = ClientHtml.addCustomCSS(html) | 104 | html = ClientHtml.addCustomCSS(html) |
105 | html = await ClientHtml.addAsyncPluginCSS(html) | 105 | html = await ClientHtml.addAsyncPluginCSS(html) |
106 | 106 | ||
107 | ClientHtml.htmlCache[ path ] = html | 107 | ClientHtml.htmlCache[path] = html |
108 | 108 | ||
109 | return html | 109 | return html |
110 | } | 110 | } |
@@ -214,21 +214,21 @@ export class ClientHtml { | |||
214 | const schemaTags = { | 214 | const schemaTags = { |
215 | '@context': 'http://schema.org', | 215 | '@context': 'http://schema.org', |
216 | '@type': 'VideoObject', | 216 | '@type': 'VideoObject', |
217 | name: videoNameEscaped, | 217 | 'name': videoNameEscaped, |
218 | description: videoDescriptionEscaped, | 218 | 'description': videoDescriptionEscaped, |
219 | thumbnailUrl: previewUrl, | 219 | 'thumbnailUrl': previewUrl, |
220 | uploadDate: video.createdAt.toISOString(), | 220 | 'uploadDate': video.createdAt.toISOString(), |
221 | duration: getActivityStreamDuration(video.duration), | 221 | 'duration': getActivityStreamDuration(video.duration), |
222 | contentUrl: videoUrl, | 222 | 'contentUrl': videoUrl, |
223 | embedUrl: embedUrl, | 223 | 'embedUrl': embedUrl, |
224 | interactionCount: video.views | 224 | 'interactionCount': video.views |
225 | } | 225 | } |
226 | 226 | ||
227 | let tagsString = '' | 227 | let tagsString = '' |
228 | 228 | ||
229 | // Opengraph | 229 | // Opengraph |
230 | Object.keys(openGraphMetaTags).forEach(tagName => { | 230 | Object.keys(openGraphMetaTags).forEach(tagName => { |
231 | const tagValue = openGraphMetaTags[ tagName ] | 231 | const tagValue = openGraphMetaTags[tagName] |
232 | 232 | ||
233 | tagsString += `<meta property="${tagName}" content="${tagValue}" />` | 233 | tagsString += `<meta property="${tagName}" content="${tagValue}" />` |
234 | }) | 234 | }) |
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index 7484524a4..9ce6186b1 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts | |||
@@ -32,7 +32,8 @@ class Emailer { | |||
32 | private initialized = false | 32 | private initialized = false |
33 | private transporter: Transporter | 33 | private transporter: Transporter |
34 | 34 | ||
35 | private constructor () {} | 35 | private constructor () { |
36 | } | ||
36 | 37 | ||
37 | init () { | 38 | init () { |
38 | // Already initialized | 39 | // Already initialized |
@@ -97,12 +98,12 @@ class Emailer { | |||
97 | const channelName = video.VideoChannel.getDisplayName() | 98 | const channelName = video.VideoChannel.getDisplayName() |
98 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() | 99 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() |
99 | 100 | ||
100 | const text = `Hi dear user,\n\n` + | 101 | const text = 'Hi dear user,\n\n' + |
101 | `Your subscription ${channelName} just published a new video: ${video.name}` + | 102 | `Your subscription ${channelName} just published a new video: ${video.name}` + |
102 | `\n\n` + | 103 | '\n\n' + |
103 | `You can view it on ${videoUrl} ` + | 104 | `You can view it on ${videoUrl} ` + |
104 | `\n\n` + | 105 | '\n\n' + |
105 | `Cheers,\n` + | 106 | 'Cheers,\n' + |
106 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 107 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
107 | 108 | ||
108 | const emailPayload: EmailPayload = { | 109 | const emailPayload: EmailPayload = { |
@@ -118,10 +119,10 @@ class Emailer { | |||
118 | const followerName = actorFollow.ActorFollower.Account.getDisplayName() | 119 | const followerName = actorFollow.ActorFollower.Account.getDisplayName() |
119 | const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName() | 120 | const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName() |
120 | 121 | ||
121 | const text = `Hi dear user,\n\n` + | 122 | const text = 'Hi dear user,\n\n' + |
122 | `Your ${followType} ${followingName} has a new subscriber: ${followerName}` + | 123 | `Your ${followType} ${followingName} has a new subscriber: ${followerName}` + |
123 | `\n\n` + | 124 | '\n\n' + |
124 | `Cheers,\n` + | 125 | 'Cheers,\n' + |
125 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 126 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
126 | 127 | ||
127 | const emailPayload: EmailPayload = { | 128 | const emailPayload: EmailPayload = { |
@@ -136,10 +137,10 @@ class Emailer { | |||
136 | addNewInstanceFollowerNotification (to: string[], actorFollow: MActorFollowActors) { | 137 | addNewInstanceFollowerNotification (to: string[], actorFollow: MActorFollowActors) { |
137 | const awaitingApproval = actorFollow.state === 'pending' ? ' awaiting manual approval.' : '' | 138 | const awaitingApproval = actorFollow.state === 'pending' ? ' awaiting manual approval.' : '' |
138 | 139 | ||
139 | const text = `Hi dear admin,\n\n` + | 140 | const text = 'Hi dear admin,\n\n' + |
140 | `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` + | 141 | `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` + |
141 | `\n\n` + | 142 | '\n\n' + |
142 | `Cheers,\n` + | 143 | 'Cheers,\n' + |
143 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 144 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
144 | 145 | ||
145 | const emailPayload: EmailPayload = { | 146 | const emailPayload: EmailPayload = { |
@@ -152,10 +153,10 @@ class Emailer { | |||
152 | } | 153 | } |
153 | 154 | ||
154 | addAutoInstanceFollowingNotification (to: string[], actorFollow: MActorFollowActors) { | 155 | addAutoInstanceFollowingNotification (to: string[], actorFollow: MActorFollowActors) { |
155 | const text = `Hi dear admin,\n\n` + | 156 | const text = 'Hi dear admin,\n\n' + |
156 | `Your instance automatically followed a new instance: ${actorFollow.ActorFollowing.url}` + | 157 | `Your instance automatically followed a new instance: ${actorFollow.ActorFollowing.url}` + |
157 | `\n\n` + | 158 | '\n\n' + |
158 | `Cheers,\n` + | 159 | 'Cheers,\n' + |
159 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 160 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
160 | 161 | ||
161 | const emailPayload: EmailPayload = { | 162 | const emailPayload: EmailPayload = { |
@@ -170,12 +171,12 @@ class Emailer { | |||
170 | myVideoPublishedNotification (to: string[], video: MVideo) { | 171 | myVideoPublishedNotification (to: string[], video: MVideo) { |
171 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() | 172 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() |
172 | 173 | ||
173 | const text = `Hi dear user,\n\n` + | 174 | const text = 'Hi dear user,\n\n' + |
174 | `Your video ${video.name} has been published.` + | 175 | `Your video ${video.name} has been published.` + |
175 | `\n\n` + | 176 | '\n\n' + |
176 | `You can view it on ${videoUrl} ` + | 177 | `You can view it on ${videoUrl} ` + |
177 | `\n\n` + | 178 | '\n\n' + |
178 | `Cheers,\n` + | 179 | 'Cheers,\n' + |
179 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 180 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
180 | 181 | ||
181 | const emailPayload: EmailPayload = { | 182 | const emailPayload: EmailPayload = { |
@@ -190,12 +191,12 @@ class Emailer { | |||
190 | myVideoImportSuccessNotification (to: string[], videoImport: MVideoImportVideo) { | 191 | myVideoImportSuccessNotification (to: string[], videoImport: MVideoImportVideo) { |
191 | const videoUrl = WEBSERVER.URL + videoImport.Video.getWatchStaticPath() | 192 | const videoUrl = WEBSERVER.URL + videoImport.Video.getWatchStaticPath() |
192 | 193 | ||
193 | const text = `Hi dear user,\n\n` + | 194 | const text = 'Hi dear user,\n\n' + |
194 | `Your video import ${videoImport.getTargetIdentifier()} is finished.` + | 195 | `Your video import ${videoImport.getTargetIdentifier()} is finished.` + |
195 | `\n\n` + | 196 | '\n\n' + |
196 | `You can view the imported video on ${videoUrl} ` + | 197 | `You can view the imported video on ${videoUrl} ` + |
197 | `\n\n` + | 198 | '\n\n' + |
198 | `Cheers,\n` + | 199 | 'Cheers,\n' + |
199 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 200 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
200 | 201 | ||
201 | const emailPayload: EmailPayload = { | 202 | const emailPayload: EmailPayload = { |
@@ -210,12 +211,12 @@ class Emailer { | |||
210 | myVideoImportErrorNotification (to: string[], videoImport: MVideoImport) { | 211 | myVideoImportErrorNotification (to: string[], videoImport: MVideoImport) { |
211 | const importUrl = WEBSERVER.URL + '/my-account/video-imports' | 212 | const importUrl = WEBSERVER.URL + '/my-account/video-imports' |
212 | 213 | ||
213 | const text = `Hi dear user,\n\n` + | 214 | const text = 'Hi dear user,\n\n' + |
214 | `Your video import ${videoImport.getTargetIdentifier()} encountered an error.` + | 215 | `Your video import ${videoImport.getTargetIdentifier()} encountered an error.` + |
215 | `\n\n` + | 216 | '\n\n' + |
216 | `See your videos import dashboard for more information: ${importUrl}` + | 217 | `See your videos import dashboard for more information: ${importUrl}` + |
217 | `\n\n` + | 218 | '\n\n' + |
218 | `Cheers,\n` + | 219 | 'Cheers,\n' + |
219 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 220 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
220 | 221 | ||
221 | const emailPayload: EmailPayload = { | 222 | const emailPayload: EmailPayload = { |
@@ -232,12 +233,12 @@ class Emailer { | |||
232 | const video = comment.Video | 233 | const video = comment.Video |
233 | const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() | 234 | const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() |
234 | 235 | ||
235 | const text = `Hi dear user,\n\n` + | 236 | const text = 'Hi dear user,\n\n' + |
236 | `A new comment has been posted by ${accountName} on your video ${video.name}` + | 237 | `A new comment has been posted by ${accountName} on your video ${video.name}` + |
237 | `\n\n` + | 238 | '\n\n' + |
238 | `You can view it on ${commentUrl} ` + | 239 | `You can view it on ${commentUrl} ` + |
239 | `\n\n` + | 240 | '\n\n' + |
240 | `Cheers,\n` + | 241 | 'Cheers,\n' + |
241 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 242 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
242 | 243 | ||
243 | const emailPayload: EmailPayload = { | 244 | const emailPayload: EmailPayload = { |
@@ -254,12 +255,12 @@ class Emailer { | |||
254 | const video = comment.Video | 255 | const video = comment.Video |
255 | const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() | 256 | const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() |
256 | 257 | ||
257 | const text = `Hi dear user,\n\n` + | 258 | const text = 'Hi dear user,\n\n' + |
258 | `${accountName} mentioned you on video ${video.name}` + | 259 | `${accountName} mentioned you on video ${video.name}` + |
259 | `\n\n` + | 260 | '\n\n' + |
260 | `You can view the comment on ${commentUrl} ` + | 261 | `You can view the comment on ${commentUrl} ` + |
261 | `\n\n` + | 262 | '\n\n' + |
262 | `Cheers,\n` + | 263 | 'Cheers,\n' + |
263 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 264 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
264 | 265 | ||
265 | const emailPayload: EmailPayload = { | 266 | const emailPayload: EmailPayload = { |
@@ -274,9 +275,9 @@ class Emailer { | |||
274 | addVideoAbuseModeratorsNotification (to: string[], videoAbuse: MVideoAbuseVideo) { | 275 | addVideoAbuseModeratorsNotification (to: string[], videoAbuse: MVideoAbuseVideo) { |
275 | const videoUrl = WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath() | 276 | const videoUrl = WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath() |
276 | 277 | ||
277 | const text = `Hi,\n\n` + | 278 | const text = 'Hi,\n\n' + |
278 | `${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` + | 279 | `${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` + |
279 | `Cheers,\n` + | 280 | 'Cheers,\n' + |
280 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 281 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
281 | 282 | ||
282 | const emailPayload: EmailPayload = { | 283 | const emailPayload: EmailPayload = { |
@@ -292,14 +293,14 @@ class Emailer { | |||
292 | const VIDEO_AUTO_BLACKLIST_URL = WEBSERVER.URL + '/admin/moderation/video-auto-blacklist/list' | 293 | const VIDEO_AUTO_BLACKLIST_URL = WEBSERVER.URL + '/admin/moderation/video-auto-blacklist/list' |
293 | const videoUrl = WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath() | 294 | const videoUrl = WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath() |
294 | 295 | ||
295 | const text = `Hi,\n\n` + | 296 | const text = 'Hi,\n\n' + |
296 | `A recently added video was auto-blacklisted and requires moderator review before publishing.` + | 297 | 'A recently added video was auto-blacklisted and requires moderator review before publishing.' + |
297 | `\n\n` + | 298 | '\n\n' + |
298 | `You can view it and take appropriate action on ${videoUrl}` + | 299 | `You can view it and take appropriate action on ${videoUrl}` + |
299 | `\n\n` + | 300 | '\n\n' + |
300 | `A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` + | 301 | `A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` + |
301 | `\n\n` + | 302 | '\n\n' + |
302 | `Cheers,\n` + | 303 | 'Cheers,\n' + |
303 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 304 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
304 | 305 | ||
305 | const emailPayload: EmailPayload = { | 306 | const emailPayload: EmailPayload = { |
@@ -312,9 +313,9 @@ class Emailer { | |||
312 | } | 313 | } |
313 | 314 | ||
314 | addNewUserRegistrationNotification (to: string[], user: MUser) { | 315 | addNewUserRegistrationNotification (to: string[], user: MUser) { |
315 | const text = `Hi,\n\n` + | 316 | const text = 'Hi,\n\n' + |
316 | `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` + | 317 | `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` + |
317 | `Cheers,\n` + | 318 | 'Cheers,\n' + |
318 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 319 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
319 | 320 | ||
320 | const emailPayload: EmailPayload = { | 321 | const emailPayload: EmailPayload = { |
@@ -367,11 +368,11 @@ class Emailer { | |||
367 | } | 368 | } |
368 | 369 | ||
369 | addPasswordResetEmailJob (to: string, resetPasswordUrl: string) { | 370 | addPasswordResetEmailJob (to: string, resetPasswordUrl: string) { |
370 | const text = `Hi dear user,\n\n` + | 371 | const text = 'Hi dear user,\n\n' + |
371 | `A reset password procedure for your account ${to} has been requested on ${WEBSERVER.HOST} ` + | 372 | `A reset password procedure for your account ${to} has been requested on ${WEBSERVER.HOST} ` + |
372 | `Please follow this link to reset it: ${resetPasswordUrl} (the link will expire within 1 hour)\n\n` + | 373 | `Please follow this link to reset it: ${resetPasswordUrl} (the link will expire within 1 hour)\n\n` + |
373 | `If you are not the person who initiated this request, please ignore this email.\n\n` + | 374 | 'If you are not the person who initiated this request, please ignore this email.\n\n' + |
374 | `Cheers,\n` + | 375 | 'Cheers,\n' + |
375 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 376 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
376 | 377 | ||
377 | const emailPayload: EmailPayload = { | 378 | const emailPayload: EmailPayload = { |
@@ -384,11 +385,11 @@ class Emailer { | |||
384 | } | 385 | } |
385 | 386 | ||
386 | addVerifyEmailJob (to: string, verifyEmailUrl: string) { | 387 | addVerifyEmailJob (to: string, verifyEmailUrl: string) { |
387 | const text = `Welcome to PeerTube,\n\n` + | 388 | const text = 'Welcome to PeerTube,\n\n' + |
388 | `To start using PeerTube on ${WEBSERVER.HOST} you must verify your email! ` + | 389 | `To start using PeerTube on ${WEBSERVER.HOST} you must verify your email! ` + |
389 | `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` + | 390 | `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` + |
390 | `If you are not the person who initiated this request, please ignore this email.\n\n` + | 391 | 'If you are not the person who initiated this request, please ignore this email.\n\n' + |
391 | `Cheers,\n` + | 392 | 'Cheers,\n' + |
392 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 393 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
393 | 394 | ||
394 | const emailPayload: EmailPayload = { | 395 | const emailPayload: EmailPayload = { |
diff --git a/server/lib/files-cache/videos-caption-cache.ts b/server/lib/files-cache/videos-caption-cache.ts index 440c3fde8..26ab3bd0d 100644 --- a/server/lib/files-cache/videos-caption-cache.ts +++ b/server/lib/files-cache/videos-caption-cache.ts | |||
@@ -5,7 +5,7 @@ import { VideoCaptionModel } from '../../models/video/video-caption' | |||
5 | import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' | 5 | import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' |
6 | import { CONFIG } from '../../initializers/config' | 6 | import { CONFIG } from '../../initializers/config' |
7 | import { logger } from '../../helpers/logger' | 7 | import { logger } from '../../helpers/logger' |
8 | import { fetchRemoteVideoStaticFile } from '../activitypub' | 8 | import { doRequestAndSaveToFile } from '@server/helpers/requests' |
9 | 9 | ||
10 | type GetPathParam = { videoId: string, language: string } | 10 | type GetPathParam = { videoId: string, language: string } |
11 | 11 | ||
@@ -46,11 +46,10 @@ class VideosCaptionCache extends AbstractVideoStaticFileCache <GetPathParam> { | |||
46 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoId) | 46 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoId) |
47 | if (!video) return undefined | 47 | if (!video) return undefined |
48 | 48 | ||
49 | // FIXME: use URL | 49 | const remoteUrl = videoCaption.getFileUrl(video) |
50 | const remoteStaticPath = videoCaption.getCaptionStaticPath() | ||
51 | const destPath = join(FILES_CACHE.VIDEO_CAPTIONS.DIRECTORY, videoCaption.getCaptionName()) | 50 | const destPath = join(FILES_CACHE.VIDEO_CAPTIONS.DIRECTORY, videoCaption.getCaptionName()) |
52 | 51 | ||
53 | await fetchRemoteVideoStaticFile(video, remoteStaticPath, destPath) | 52 | await doRequestAndSaveToFile({ uri: remoteUrl }, destPath) |
54 | 53 | ||
55 | return { isOwned: false, path: destPath } | 54 | return { isOwned: false, path: destPath } |
56 | } | 55 | } |
diff --git a/server/lib/files-cache/videos-preview-cache.ts b/server/lib/files-cache/videos-preview-cache.ts index 3da6bb138..d0d4fc5b5 100644 --- a/server/lib/files-cache/videos-preview-cache.ts +++ b/server/lib/files-cache/videos-preview-cache.ts | |||
@@ -1,9 +1,8 @@ | |||
1 | import { join } from 'path' | 1 | import { join } from 'path' |
2 | import { FILES_CACHE, STATIC_PATHS } from '../../initializers/constants' | 2 | import { FILES_CACHE } from '../../initializers/constants' |
3 | import { VideoModel } from '../../models/video/video' | 3 | import { VideoModel } from '../../models/video/video' |
4 | import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' | 4 | import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' |
5 | import { CONFIG } from '../../initializers/config' | 5 | import { doRequestAndSaveToFile } from '@server/helpers/requests' |
6 | import { fetchRemoteVideoStaticFile } from '../activitypub' | ||
7 | 6 | ||
8 | class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { | 7 | class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { |
9 | 8 | ||
@@ -32,11 +31,11 @@ class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { | |||
32 | 31 | ||
33 | if (video.isOwned()) throw new Error('Cannot load remote preview of owned video.') | 32 | if (video.isOwned()) throw new Error('Cannot load remote preview of owned video.') |
34 | 33 | ||
35 | // FIXME: use URL | 34 | const preview = video.getPreview() |
36 | const remoteStaticPath = join(STATIC_PATHS.PREVIEWS, video.getPreview().filename) | 35 | const destPath = join(FILES_CACHE.PREVIEWS.DIRECTORY, preview.filename) |
37 | const destPath = join(FILES_CACHE.PREVIEWS.DIRECTORY, video.getPreview().filename) | ||
38 | 36 | ||
39 | await fetchRemoteVideoStaticFile(video, remoteStaticPath, destPath) | 37 | const remoteUrl = preview.getFileUrl(video) |
38 | await doRequestAndSaveToFile({ uri: remoteUrl }, destPath) | ||
40 | 39 | ||
41 | return { isOwned: false, path: destPath } | 40 | return { isOwned: false, path: destPath } |
42 | } | 41 | } |
diff --git a/server/lib/job-queue/handlers/activitypub-http-broadcast.ts b/server/lib/job-queue/handlers/activitypub-http-broadcast.ts index 0ff7b44a0..7d9dd61e9 100644 --- a/server/lib/job-queue/handlers/activitypub-http-broadcast.ts +++ b/server/lib/job-queue/handlers/activitypub-http-broadcast.ts | |||
@@ -5,11 +5,13 @@ import { doRequest } from '../../../helpers/requests' | |||
5 | import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils' | 5 | import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils' |
6 | import { BROADCAST_CONCURRENCY, JOB_REQUEST_TIMEOUT } from '../../../initializers/constants' | 6 | import { BROADCAST_CONCURRENCY, JOB_REQUEST_TIMEOUT } from '../../../initializers/constants' |
7 | import { ActorFollowScoreCache } from '../../files-cache' | 7 | import { ActorFollowScoreCache } from '../../files-cache' |
8 | import { ContextType } from '@server/helpers/activitypub' | ||
8 | 9 | ||
9 | export type ActivitypubHttpBroadcastPayload = { | 10 | export type ActivitypubHttpBroadcastPayload = { |
10 | uris: string[] | 11 | uris: string[] |
11 | signatureActorId?: number | 12 | signatureActorId?: number |
12 | body: any | 13 | body: any |
14 | contextType?: ContextType | ||
13 | } | 15 | } |
14 | 16 | ||
15 | async function processActivityPubHttpBroadcast (job: Bull.Job) { | 17 | async function processActivityPubHttpBroadcast (job: Bull.Job) { |
diff --git a/server/lib/job-queue/handlers/activitypub-http-unicast.ts b/server/lib/job-queue/handlers/activitypub-http-unicast.ts index c70ce3be9..6b71e2891 100644 --- a/server/lib/job-queue/handlers/activitypub-http-unicast.ts +++ b/server/lib/job-queue/handlers/activitypub-http-unicast.ts | |||
@@ -4,11 +4,13 @@ import { doRequest } from '../../../helpers/requests' | |||
4 | import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils' | 4 | import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils' |
5 | import { JOB_REQUEST_TIMEOUT } from '../../../initializers/constants' | 5 | import { JOB_REQUEST_TIMEOUT } from '../../../initializers/constants' |
6 | import { ActorFollowScoreCache } from '../../files-cache' | 6 | import { ActorFollowScoreCache } from '../../files-cache' |
7 | import { ContextType } from '@server/helpers/activitypub' | ||
7 | 8 | ||
8 | export type ActivitypubHttpUnicastPayload = { | 9 | export type ActivitypubHttpUnicastPayload = { |
9 | uri: string | 10 | uri: string |
10 | signatureActorId?: number | 11 | signatureActorId?: number |
11 | body: any | 12 | body: any |
13 | contextType?: ContextType | ||
12 | } | 14 | } |
13 | 15 | ||
14 | async function processActivityPubHttpUnicast (job: Bull.Job) { | 16 | async function processActivityPubHttpUnicast (job: Bull.Job) { |
diff --git a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts index d3bde6e6a..54b35840d 100644 --- a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts +++ b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import { buildSignedActivity } from '../../../../helpers/activitypub' | 1 | import { buildSignedActivity, ContextType } from '../../../../helpers/activitypub' |
2 | import { getServerActor } from '../../../../helpers/utils' | 2 | import { getServerActor } from '../../../../helpers/utils' |
3 | import { ActorModel } from '../../../../models/activitypub/actor' | 3 | import { ActorModel } from '../../../../models/activitypub/actor' |
4 | import { sha256 } from '../../../../helpers/core-utils' | 4 | import { sha256 } from '../../../../helpers/core-utils' |
5 | import { HTTP_SIGNATURE } from '../../../../initializers/constants' | 5 | import { HTTP_SIGNATURE } from '../../../../initializers/constants' |
6 | import { MActor } from '../../../../typings/models' | 6 | import { MActor } from '../../../../typings/models' |
7 | 7 | ||
8 | type Payload = { body: any, signatureActorId?: number } | 8 | type Payload = { body: any, contextType?: ContextType, signatureActorId?: number } |
9 | 9 | ||
10 | async function computeBody (payload: Payload) { | 10 | async function computeBody (payload: Payload) { |
11 | let body = payload.body | 11 | let body = payload.body |
@@ -13,7 +13,7 @@ async function computeBody (payload: Payload) { | |||
13 | if (payload.signatureActorId) { | 13 | if (payload.signatureActorId) { |
14 | const actorSignature = await ActorModel.load(payload.signatureActorId) | 14 | const actorSignature = await ActorModel.load(payload.signatureActorId) |
15 | if (!actorSignature) throw new Error('Unknown signature actor id.') | 15 | if (!actorSignature) throw new Error('Unknown signature actor id.') |
16 | body = await buildSignedActivity(actorSignature, payload.body) | 16 | body = await buildSignedActivity(actorSignature, payload.body, payload.contextType) |
17 | } | 17 | } |
18 | 18 | ||
19 | return body | 19 | return body |
@@ -42,7 +42,7 @@ async function buildSignedRequestOptions (payload: Payload) { | |||
42 | 42 | ||
43 | function buildGlobalHeaders (body: any) { | 43 | function buildGlobalHeaders (body: any) { |
44 | return { | 44 | return { |
45 | 'Digest': buildDigest(body) | 45 | Digest: buildDigest(body) |
46 | } | 46 | } |
47 | } | 47 | } |
48 | 48 | ||
diff --git a/server/lib/job-queue/handlers/video-file-import.ts b/server/lib/job-queue/handlers/video-file-import.ts index 99c991e72..be9e7d181 100644 --- a/server/lib/job-queue/handlers/video-file-import.ts +++ b/server/lib/job-queue/handlers/video-file-import.ts | |||
@@ -11,7 +11,7 @@ import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' | |||
11 | import { getVideoFilePath } from '@server/lib/video-paths' | 11 | import { getVideoFilePath } from '@server/lib/video-paths' |
12 | 12 | ||
13 | export type VideoFileImportPayload = { | 13 | export type VideoFileImportPayload = { |
14 | videoUUID: string, | 14 | videoUUID: string |
15 | filePath: string | 15 | filePath: string |
16 | } | 16 | } |
17 | 17 | ||
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts index 1fca17584..09f225cec 100644 --- a/server/lib/job-queue/handlers/video-import.ts +++ b/server/lib/job-queue/handlers/video-import.ts | |||
@@ -221,7 +221,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid | |||
221 | isNewVideo: true | 221 | isNewVideo: true |
222 | } | 222 | } |
223 | 223 | ||
224 | await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) | 224 | await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: dataInput }) |
225 | } | 225 | } |
226 | 226 | ||
227 | } catch (err) { | 227 | } catch (err) { |
diff --git a/server/lib/job-queue/handlers/video-redundancy.ts b/server/lib/job-queue/handlers/video-redundancy.ts new file mode 100644 index 000000000..319d7090e --- /dev/null +++ b/server/lib/job-queue/handlers/video-redundancy.ts | |||
@@ -0,0 +1,20 @@ | |||
1 | import * as Bull from 'bull' | ||
2 | import { logger } from '../../../helpers/logger' | ||
3 | import { VideosRedundancyScheduler } from '@server/lib/schedulers/videos-redundancy-scheduler' | ||
4 | |||
5 | export type VideoRedundancyPayload = { | ||
6 | videoId: number | ||
7 | } | ||
8 | |||
9 | async function processVideoRedundancy (job: Bull.Job) { | ||
10 | const payload = job.data as VideoRedundancyPayload | ||
11 | logger.info('Processing video redundancy in job %d.', job.id) | ||
12 | |||
13 | return VideosRedundancyScheduler.Instance.createManualRedundancy(payload.videoId) | ||
14 | } | ||
15 | |||
16 | // --------------------------------------------------------------------------- | ||
17 | |||
18 | export { | ||
19 | processVideoRedundancy | ||
20 | } | ||
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts index 39b9fac98..c020057c9 100644 --- a/server/lib/job-queue/handlers/video-transcoding.ts +++ b/server/lib/job-queue/handlers/video-transcoding.ts | |||
@@ -6,7 +6,6 @@ import { JobQueue } from '../job-queue' | |||
6 | import { federateVideoIfNeeded } from '../../activitypub' | 6 | import { federateVideoIfNeeded } from '../../activitypub' |
7 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 7 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
8 | import { sequelizeTypescript } from '../../../initializers' | 8 | import { sequelizeTypescript } from '../../../initializers' |
9 | import * as Bluebird from 'bluebird' | ||
10 | import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' | 9 | import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' |
11 | import { generateHlsPlaylist, mergeAudioVideofile, optimizeOriginalVideofile, transcodeNewResolution } from '../../video-transcoding' | 10 | import { generateHlsPlaylist, mergeAudioVideofile, optimizeOriginalVideofile, transcodeNewResolution } from '../../video-transcoding' |
12 | import { Notifier } from '../../notifier' | 11 | import { Notifier } from '../../notifier' |
@@ -40,8 +39,11 @@ interface OptimizeTranscodingPayload extends BaseTranscodingPayload { | |||
40 | type: 'optimize' | 39 | type: 'optimize' |
41 | } | 40 | } |
42 | 41 | ||
43 | export type VideoTranscodingPayload = HLSTranscodingPayload | NewResolutionTranscodingPayload | 42 | export type VideoTranscodingPayload = |
44 | | OptimizeTranscodingPayload | MergeAudioTranscodingPayload | 43 | HLSTranscodingPayload |
44 | | NewResolutionTranscodingPayload | ||
45 | | OptimizeTranscodingPayload | ||
46 | | MergeAudioTranscodingPayload | ||
45 | 47 | ||
46 | async function processVideoTranscoding (job: Bull.Job) { | 48 | async function processVideoTranscoding (job: Bull.Job) { |
47 | const payload = job.data as VideoTranscodingPayload | 49 | const payload = job.data as VideoTranscodingPayload |
@@ -105,7 +107,7 @@ async function onVideoFileOptimizerSuccess (videoArg: MVideoWithFile, payload: O | |||
105 | 107 | ||
106 | const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => { | 108 | const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => { |
107 | // Maybe the video changed in database, refresh it | 109 | // Maybe the video changed in database, refresh it |
108 | let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid, t) | 110 | const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid, t) |
109 | // Video does not exist anymore | 111 | // Video does not exist anymore |
110 | if (!videoDatabase) return undefined | 112 | if (!videoDatabase) return undefined |
111 | 113 | ||
@@ -122,8 +124,6 @@ async function onVideoFileOptimizerSuccess (videoArg: MVideoWithFile, payload: O | |||
122 | await createHlsJobIfEnabled(hlsPayload) | 124 | await createHlsJobIfEnabled(hlsPayload) |
123 | 125 | ||
124 | if (resolutionsEnabled.length !== 0) { | 126 | if (resolutionsEnabled.length !== 0) { |
125 | const tasks: (Bluebird<Bull.Job<any>> | Promise<Bull.Job<any>>)[] = [] | ||
126 | |||
127 | for (const resolution of resolutionsEnabled) { | 127 | for (const resolution of resolutionsEnabled) { |
128 | let dataInput: VideoTranscodingPayload | 128 | let dataInput: VideoTranscodingPayload |
129 | 129 | ||
@@ -143,12 +143,9 @@ async function onVideoFileOptimizerSuccess (videoArg: MVideoWithFile, payload: O | |||
143 | } | 143 | } |
144 | } | 144 | } |
145 | 145 | ||
146 | const p = JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) | 146 | JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) |
147 | tasks.push(p) | ||
148 | } | 147 | } |
149 | 148 | ||
150 | await Promise.all(tasks) | ||
151 | |||
152 | logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled }) | 149 | logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled }) |
153 | } else { | 150 | } else { |
154 | // No transcoding to do, it's now published | 151 | // No transcoding to do, it's now published |
diff --git a/server/lib/job-queue/handlers/video-views.ts b/server/lib/job-queue/handlers/video-views.ts index 73fa5ed04..2258cd029 100644 --- a/server/lib/job-queue/handlers/video-views.ts +++ b/server/lib/job-queue/handlers/video-views.ts | |||
@@ -23,6 +23,8 @@ async function processVideosViews () { | |||
23 | for (const videoId of videoIds) { | 23 | for (const videoId of videoIds) { |
24 | try { | 24 | try { |
25 | const views = await Redis.Instance.getVideoViews(videoId, hour) | 25 | const views = await Redis.Instance.getVideoViews(videoId, hour) |
26 | await Redis.Instance.deleteVideoViews(videoId, hour) | ||
27 | |||
26 | if (views) { | 28 | if (views) { |
27 | logger.debug('Adding %d views to video %d in hour %d.', views, videoId, hour) | 29 | logger.debug('Adding %d views to video %d in hour %d.', views, videoId, hour) |
28 | 30 | ||
@@ -52,8 +54,6 @@ async function processVideosViews () { | |||
52 | logger.error('Cannot create video views for video %d in hour %d.', videoId, hour, { err }) | 54 | logger.error('Cannot create video views for video %d in hour %d.', videoId, hour, { err }) |
53 | } | 55 | } |
54 | } | 56 | } |
55 | |||
56 | await Redis.Instance.deleteVideoViews(videoId, hour) | ||
57 | } catch (err) { | 57 | } catch (err) { |
58 | logger.error('Cannot update video views of video %d in hour %d.', videoId, hour, { err }) | 58 | logger.error('Cannot update video views of video %d in hour %d.', videoId, hour, { err }) |
59 | } | 59 | } |
diff --git a/server/lib/job-queue/job-queue.ts b/server/lib/job-queue/job-queue.ts index ec601e9ea..14acace7d 100644 --- a/server/lib/job-queue/job-queue.ts +++ b/server/lib/job-queue/job-queue.ts | |||
@@ -13,6 +13,7 @@ import { processVideoImport, VideoImportPayload } from './handlers/video-import' | |||
13 | import { processVideosViews } from './handlers/video-views' | 13 | import { processVideosViews } from './handlers/video-views' |
14 | import { refreshAPObject, RefreshPayload } from './handlers/activitypub-refresher' | 14 | import { refreshAPObject, RefreshPayload } from './handlers/activitypub-refresher' |
15 | import { processVideoFileImport, VideoFileImportPayload } from './handlers/video-file-import' | 15 | import { processVideoFileImport, VideoFileImportPayload } from './handlers/video-file-import' |
16 | import { processVideoRedundancy, VideoRedundancyPayload } from '@server/lib/job-queue/handlers/video-redundancy' | ||
16 | 17 | ||
17 | type CreateJobArgument = | 18 | type CreateJobArgument = |
18 | { type: 'activitypub-http-broadcast', payload: ActivitypubHttpBroadcastPayload } | | 19 | { type: 'activitypub-http-broadcast', payload: ActivitypubHttpBroadcastPayload } | |
@@ -24,20 +25,21 @@ type CreateJobArgument = | |||
24 | { type: 'email', payload: EmailPayload } | | 25 | { type: 'email', payload: EmailPayload } | |
25 | { type: 'video-import', payload: VideoImportPayload } | | 26 | { type: 'video-import', payload: VideoImportPayload } | |
26 | { type: 'activitypub-refresher', payload: RefreshPayload } | | 27 | { type: 'activitypub-refresher', payload: RefreshPayload } | |
27 | { type: 'videos-views', payload: {} } | 28 | { type: 'videos-views', payload: {} } | |
29 | { type: 'video-redundancy', payload: VideoRedundancyPayload } | ||
28 | 30 | ||
29 | const handlers: { [ id in (JobType | 'video-file') ]: (job: Bull.Job) => Promise<any>} = { | 31 | const handlers: { [id in JobType]: (job: Bull.Job) => Promise<any> } = { |
30 | 'activitypub-http-broadcast': processActivityPubHttpBroadcast, | 32 | 'activitypub-http-broadcast': processActivityPubHttpBroadcast, |
31 | 'activitypub-http-unicast': processActivityPubHttpUnicast, | 33 | 'activitypub-http-unicast': processActivityPubHttpUnicast, |
32 | 'activitypub-http-fetcher': processActivityPubHttpFetcher, | 34 | 'activitypub-http-fetcher': processActivityPubHttpFetcher, |
33 | 'activitypub-follow': processActivityPubFollow, | 35 | 'activitypub-follow': processActivityPubFollow, |
34 | 'video-file-import': processVideoFileImport, | 36 | 'video-file-import': processVideoFileImport, |
35 | 'video-transcoding': processVideoTranscoding, | 37 | 'video-transcoding': processVideoTranscoding, |
36 | 'video-file': processVideoTranscoding, // TODO: remove it (changed in 1.3) | ||
37 | 'email': processEmail, | 38 | 'email': processEmail, |
38 | 'video-import': processVideoImport, | 39 | 'video-import': processVideoImport, |
39 | 'videos-views': processVideosViews, | 40 | 'videos-views': processVideosViews, |
40 | 'activitypub-refresher': refreshAPObject | 41 | 'activitypub-refresher': refreshAPObject, |
42 | 'video-redundancy': processVideoRedundancy | ||
41 | } | 43 | } |
42 | 44 | ||
43 | const jobTypes: JobType[] = [ | 45 | const jobTypes: JobType[] = [ |
@@ -50,20 +52,22 @@ const jobTypes: JobType[] = [ | |||
50 | 'video-file-import', | 52 | 'video-file-import', |
51 | 'video-import', | 53 | 'video-import', |
52 | 'videos-views', | 54 | 'videos-views', |
53 | 'activitypub-refresher' | 55 | 'activitypub-refresher', |
56 | 'video-redundancy' | ||
54 | ] | 57 | ] |
55 | 58 | ||
56 | class JobQueue { | 59 | class JobQueue { |
57 | 60 | ||
58 | private static instance: JobQueue | 61 | private static instance: JobQueue |
59 | 62 | ||
60 | private queues: { [ id in JobType ]?: Bull.Queue } = {} | 63 | private queues: { [id in JobType]?: Bull.Queue } = {} |
61 | private initialized = false | 64 | private initialized = false |
62 | private jobRedisPrefix: string | 65 | private jobRedisPrefix: string |
63 | 66 | ||
64 | private constructor () {} | 67 | private constructor () { |
68 | } | ||
65 | 69 | ||
66 | async init () { | 70 | init () { |
67 | // Already initialized | 71 | // Already initialized |
68 | if (this.initialized === true) return | 72 | if (this.initialized === true) return |
69 | this.initialized = true | 73 | this.initialized = true |
@@ -105,11 +109,16 @@ class JobQueue { | |||
105 | } | 109 | } |
106 | } | 110 | } |
107 | 111 | ||
108 | createJob (obj: CreateJobArgument) { | 112 | createJob (obj: CreateJobArgument): void { |
113 | this.createJobWithPromise(obj) | ||
114 | .catch(err => logger.error('Cannot create job.', { err, obj })) | ||
115 | } | ||
116 | |||
117 | createJobWithPromise (obj: CreateJobArgument) { | ||
109 | const queue = this.queues[obj.type] | 118 | const queue = this.queues[obj.type] |
110 | if (queue === undefined) { | 119 | if (queue === undefined) { |
111 | logger.error('Unknown queue %s: cannot create job.', obj.type) | 120 | logger.error('Unknown queue %s: cannot create job.', obj.type) |
112 | throw Error('Unknown queue, cannot create job') | 121 | return |
113 | } | 122 | } |
114 | 123 | ||
115 | const jobArgs: Bull.JobOptions = { | 124 | const jobArgs: Bull.JobOptions = { |
@@ -122,10 +131,10 @@ class JobQueue { | |||
122 | } | 131 | } |
123 | 132 | ||
124 | async listForApi (options: { | 133 | async listForApi (options: { |
125 | state: JobState, | 134 | state: JobState |
126 | start: number, | 135 | start: number |
127 | count: number, | 136 | count: number |
128 | asc?: boolean, | 137 | asc?: boolean |
129 | jobType: JobType | 138 | jobType: JobType |
130 | }): Promise<Bull.Job[]> { | 139 | }): Promise<Bull.Job[]> { |
131 | const { state, start, count, asc, jobType } = options | 140 | const { state, start, count, asc, jobType } = options |
@@ -133,16 +142,14 @@ class JobQueue { | |||
133 | 142 | ||
134 | const filteredJobTypes = this.filterJobTypes(jobType) | 143 | const filteredJobTypes = this.filterJobTypes(jobType) |
135 | 144 | ||
136 | // TODO: optimize | ||
137 | for (const jobType of filteredJobTypes) { | 145 | for (const jobType of filteredJobTypes) { |
138 | const queue = this.queues[ jobType ] | 146 | const queue = this.queues[jobType] |
139 | if (queue === undefined) { | 147 | if (queue === undefined) { |
140 | logger.error('Unknown queue %s to list jobs.', jobType) | 148 | logger.error('Unknown queue %s to list jobs.', jobType) |
141 | continue | 149 | continue |
142 | } | 150 | } |
143 | 151 | ||
144 | // FIXME: Bull queue typings does not have getJobs method | 152 | const jobs = await queue.getJobs([ state ], 0, start + count, asc) |
145 | const jobs = await (queue as any).getJobs(state, 0, start + count, asc) | ||
146 | results = results.concat(jobs) | 153 | results = results.concat(jobs) |
147 | } | 154 | } |
148 | 155 | ||
@@ -164,7 +171,7 @@ class JobQueue { | |||
164 | const filteredJobTypes = this.filterJobTypes(jobType) | 171 | const filteredJobTypes = this.filterJobTypes(jobType) |
165 | 172 | ||
166 | for (const type of filteredJobTypes) { | 173 | for (const type of filteredJobTypes) { |
167 | const queue = this.queues[ type ] | 174 | const queue = this.queues[type] |
168 | if (queue === undefined) { | 175 | if (queue === undefined) { |
169 | logger.error('Unknown queue %s to count jobs.', type) | 176 | logger.error('Unknown queue %s to count jobs.', type) |
170 | continue | 177 | continue |
@@ -172,7 +179,7 @@ class JobQueue { | |||
172 | 179 | ||
173 | const counts = await queue.getJobCounts() | 180 | const counts = await queue.getJobCounts() |
174 | 181 | ||
175 | total += counts[ state ] | 182 | total += counts[state] |
176 | } | 183 | } |
177 | 184 | ||
178 | return total | 185 | return total |
@@ -188,7 +195,7 @@ class JobQueue { | |||
188 | private addRepeatableJobs () { | 195 | private addRepeatableJobs () { |
189 | this.queues['videos-views'].add({}, { | 196 | this.queues['videos-views'].add({}, { |
190 | repeat: REPEAT_JOBS['videos-views'] | 197 | repeat: REPEAT_JOBS['videos-views'] |
191 | }) | 198 | }).catch(err => logger.error('Cannot add repeatable job.', { err })) |
192 | } | 199 | } |
193 | 200 | ||
194 | private filterJobTypes (jobType?: JobType) { | 201 | private filterJobTypes (jobType?: JobType) { |
diff --git a/server/lib/moderation.ts b/server/lib/moderation.ts index b609f4585..55f7a985d 100644 --- a/server/lib/moderation.ts +++ b/server/lib/moderation.ts | |||
@@ -15,41 +15,41 @@ export type AcceptResult = { | |||
15 | 15 | ||
16 | // Can be filtered by plugins | 16 | // Can be filtered by plugins |
17 | function isLocalVideoAccepted (object: { | 17 | function isLocalVideoAccepted (object: { |
18 | videoBody: VideoCreate, | 18 | videoBody: VideoCreate |
19 | videoFile: Express.Multer.File & { duration?: number }, | 19 | videoFile: Express.Multer.File & { duration?: number } |
20 | user: UserModel | 20 | user: UserModel |
21 | }): AcceptResult { | 21 | }): AcceptResult { |
22 | return { accepted: true } | 22 | return { accepted: true } |
23 | } | 23 | } |
24 | 24 | ||
25 | function isLocalVideoThreadAccepted (_object: { | 25 | function isLocalVideoThreadAccepted (_object: { |
26 | commentBody: VideoCommentCreate, | 26 | commentBody: VideoCommentCreate |
27 | video: VideoModel, | 27 | video: VideoModel |
28 | user: UserModel | 28 | user: UserModel |
29 | }): AcceptResult { | 29 | }): AcceptResult { |
30 | return { accepted: true } | 30 | return { accepted: true } |
31 | } | 31 | } |
32 | 32 | ||
33 | function isLocalVideoCommentReplyAccepted (_object: { | 33 | function isLocalVideoCommentReplyAccepted (_object: { |
34 | commentBody: VideoCommentCreate, | 34 | commentBody: VideoCommentCreate |
35 | parentComment: VideoCommentModel, | 35 | parentComment: VideoCommentModel |
36 | video: VideoModel, | 36 | video: VideoModel |
37 | user: UserModel | 37 | user: UserModel |
38 | }): AcceptResult { | 38 | }): AcceptResult { |
39 | return { accepted: true } | 39 | return { accepted: true } |
40 | } | 40 | } |
41 | 41 | ||
42 | function isRemoteVideoAccepted (_object: { | 42 | function isRemoteVideoAccepted (_object: { |
43 | activity: ActivityCreate, | 43 | activity: ActivityCreate |
44 | videoAP: VideoTorrentObject, | 44 | videoAP: VideoTorrentObject |
45 | byActor: ActorModel | 45 | byActor: ActorModel |
46 | }): AcceptResult { | 46 | }): AcceptResult { |
47 | return { accepted: true } | 47 | return { accepted: true } |
48 | } | 48 | } |
49 | 49 | ||
50 | function isRemoteVideoCommentAccepted (_object: { | 50 | function isRemoteVideoCommentAccepted (_object: { |
51 | activity: ActivityCreate, | 51 | activity: ActivityCreate |
52 | commentAP: VideoCommentObject, | 52 | commentAP: VideoCommentObject |
53 | byActor: ActorModel | 53 | byActor: ActorModel |
54 | }): AcceptResult { | 54 | }): AcceptResult { |
55 | return { accepted: true } | 55 | return { accepted: true } |
diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts index 679b9bcf6..63197eee1 100644 --- a/server/lib/notifier.ts +++ b/server/lib/notifier.ts | |||
@@ -6,7 +6,6 @@ import { UserModel } from '../models/account/user' | |||
6 | import { PeerTubeSocket } from './peertube-socket' | 6 | import { PeerTubeSocket } from './peertube-socket' |
7 | import { CONFIG } from '../initializers/config' | 7 | import { CONFIG } from '../initializers/config' |
8 | import { VideoPrivacy, VideoState } from '../../shared/models/videos' | 8 | import { VideoPrivacy, VideoState } from '../../shared/models/videos' |
9 | import * as Bluebird from 'bluebird' | ||
10 | import { AccountBlocklistModel } from '../models/account/account-blocklist' | 9 | import { AccountBlocklistModel } from '../models/account/account-blocklist' |
11 | import { | 10 | import { |
12 | MCommentOwnerVideo, | 11 | MCommentOwnerVideo, |
@@ -17,7 +16,8 @@ import { | |||
17 | MVideoFullLight | 16 | MVideoFullLight |
18 | } from '../typings/models/video' | 17 | } from '../typings/models/video' |
19 | import { | 18 | import { |
20 | MUser, MUserAccount, | 19 | MUser, |
20 | MUserAccount, | ||
21 | MUserDefault, | 21 | MUserDefault, |
22 | MUserNotifSettingAccount, | 22 | MUserNotifSettingAccount, |
23 | MUserWithNotificationSetting, | 23 | MUserWithNotificationSetting, |
@@ -32,14 +32,15 @@ class Notifier { | |||
32 | 32 | ||
33 | private static instance: Notifier | 33 | private static instance: Notifier |
34 | 34 | ||
35 | private constructor () {} | 35 | private constructor () { |
36 | } | ||
36 | 37 | ||
37 | notifyOnNewVideoIfNeeded (video: MVideoAccountLight): void { | 38 | notifyOnNewVideoIfNeeded (video: MVideoAccountLight): void { |
38 | // Only notify on public and published videos which are not blacklisted | 39 | // Only notify on public and published videos which are not blacklisted |
39 | if (video.privacy !== VideoPrivacy.PUBLIC || video.state !== VideoState.PUBLISHED || video.isBlacklisted()) return | 40 | if (video.privacy !== VideoPrivacy.PUBLIC || video.state !== VideoState.PUBLISHED || video.isBlacklisted()) return |
40 | 41 | ||
41 | this.notifySubscribersOfNewVideo(video) | 42 | this.notifySubscribersOfNewVideo(video) |
42 | .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err })) | 43 | .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err })) |
43 | } | 44 | } |
44 | 45 | ||
45 | notifyOnVideoPublishedAfterTranscoding (video: MVideoFullLight): void { | 46 | notifyOnVideoPublishedAfterTranscoding (video: MVideoFullLight): void { |
@@ -63,7 +64,9 @@ class Notifier { | |||
63 | if (video.ScheduleVideoUpdate || (video.waitTranscoding && video.state !== VideoState.PUBLISHED)) return | 64 | if (video.ScheduleVideoUpdate || (video.waitTranscoding && video.state !== VideoState.PUBLISHED)) return |
64 | 65 | ||
65 | this.notifyOwnedVideoHasBeenPublished(video) | 66 | this.notifyOwnedVideoHasBeenPublished(video) |
66 | .catch(err => logger.error('Cannot notify owner that its video %s has been published after removed from auto-blacklist.', video.url, { err })) // tslint:disable-line:max-line-length | 67 | .catch(err => { |
68 | logger.error('Cannot notify owner that its video %s has been published after removed from auto-blacklist.', video.url, { err }) | ||
69 | }) | ||
67 | } | 70 | } |
68 | 71 | ||
69 | notifyOnNewComment (comment: MCommentOwnerVideo): void { | 72 | notifyOnNewComment (comment: MCommentOwnerVideo): void { |
@@ -76,17 +79,17 @@ class Notifier { | |||
76 | 79 | ||
77 | notifyOnNewVideoAbuse (videoAbuse: MVideoAbuseVideo): void { | 80 | notifyOnNewVideoAbuse (videoAbuse: MVideoAbuseVideo): void { |
78 | this.notifyModeratorsOfNewVideoAbuse(videoAbuse) | 81 | this.notifyModeratorsOfNewVideoAbuse(videoAbuse) |
79 | .catch(err => logger.error('Cannot notify of new video abuse of video %s.', videoAbuse.Video.url, { err })) | 82 | .catch(err => logger.error('Cannot notify of new video abuse of video %s.', videoAbuse.Video.url, { err })) |
80 | } | 83 | } |
81 | 84 | ||
82 | notifyOnVideoAutoBlacklist (videoBlacklist: MVideoBlacklistLightVideo): void { | 85 | notifyOnVideoAutoBlacklist (videoBlacklist: MVideoBlacklistLightVideo): void { |
83 | this.notifyModeratorsOfVideoAutoBlacklist(videoBlacklist) | 86 | this.notifyModeratorsOfVideoAutoBlacklist(videoBlacklist) |
84 | .catch(err => logger.error('Cannot notify of auto-blacklist of video %s.', videoBlacklist.Video.url, { err })) | 87 | .catch(err => logger.error('Cannot notify of auto-blacklist of video %s.', videoBlacklist.Video.url, { err })) |
85 | } | 88 | } |
86 | 89 | ||
87 | notifyOnVideoBlacklist (videoBlacklist: MVideoBlacklistVideo): void { | 90 | notifyOnVideoBlacklist (videoBlacklist: MVideoBlacklistVideo): void { |
88 | this.notifyVideoOwnerOfBlacklist(videoBlacklist) | 91 | this.notifyVideoOwnerOfBlacklist(videoBlacklist) |
89 | .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err })) | 92 | .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err })) |
90 | } | 93 | } |
91 | 94 | ||
92 | notifyOnVideoUnblacklist (video: MVideoFullLight): void { | 95 | notifyOnVideoUnblacklist (video: MVideoFullLight): void { |
@@ -96,7 +99,7 @@ class Notifier { | |||
96 | 99 | ||
97 | notifyOnFinishedVideoImport (videoImport: MVideoImportVideo, success: boolean): void { | 100 | notifyOnFinishedVideoImport (videoImport: MVideoImportVideo, success: boolean): void { |
98 | this.notifyOwnerVideoImportIsFinished(videoImport, success) | 101 | this.notifyOwnerVideoImportIsFinished(videoImport, success) |
99 | .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err })) | 102 | .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err })) |
100 | } | 103 | } |
101 | 104 | ||
102 | notifyOnNewUserRegistration (user: MUserDefault): void { | 105 | notifyOnNewUserRegistration (user: MUserDefault): void { |
@@ -106,14 +109,14 @@ class Notifier { | |||
106 | 109 | ||
107 | notifyOfNewUserFollow (actorFollow: MActorFollowFull): void { | 110 | notifyOfNewUserFollow (actorFollow: MActorFollowFull): void { |
108 | this.notifyUserOfNewActorFollow(actorFollow) | 111 | this.notifyUserOfNewActorFollow(actorFollow) |
109 | .catch(err => { | 112 | .catch(err => { |
110 | logger.error( | 113 | logger.error( |
111 | 'Cannot notify owner of channel %s of a new follow by %s.', | 114 | 'Cannot notify owner of channel %s of a new follow by %s.', |
112 | actorFollow.ActorFollowing.VideoChannel.getDisplayName(), | 115 | actorFollow.ActorFollowing.VideoChannel.getDisplayName(), |
113 | actorFollow.ActorFollower.Account.getDisplayName(), | 116 | actorFollow.ActorFollower.Account.getDisplayName(), |
114 | { err } | 117 | { err } |
115 | ) | 118 | ) |
116 | }) | 119 | }) |
117 | } | 120 | } |
118 | 121 | ||
119 | notifyOfNewInstanceFollow (actorFollow: MActorFollowFull): void { | 122 | notifyOfNewInstanceFollow (actorFollow: MActorFollowFull): void { |
@@ -548,10 +551,10 @@ class Notifier { | |||
548 | return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender }) | 551 | return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender }) |
549 | } | 552 | } |
550 | 553 | ||
551 | private async notify <T extends MUserWithNotificationSetting> (options: { | 554 | private async notify<T extends MUserWithNotificationSetting> (options: { |
552 | users: T[], | 555 | users: T[] |
553 | notificationCreator: (user: T) => Promise<UserNotificationModelForApi>, | 556 | notificationCreator: (user: T) => Promise<UserNotificationModelForApi> |
554 | emailSender: (emails: string[]) => Promise<any> | Bluebird<any>, | 557 | emailSender: (emails: string[]) => void |
555 | settingGetter: (user: T) => UserNotificationSettingValue | 558 | settingGetter: (user: T) => UserNotificationSettingValue |
556 | }) { | 559 | }) { |
557 | const emails: string[] = [] | 560 | const emails: string[] = [] |
@@ -569,7 +572,7 @@ class Notifier { | |||
569 | } | 572 | } |
570 | 573 | ||
571 | if (emails.length !== 0) { | 574 | if (emails.length !== 0) { |
572 | await options.emailSender(emails) | 575 | options.emailSender(emails) |
573 | } | 576 | } |
574 | } | 577 | } |
575 | 578 | ||
diff --git a/server/lib/plugins/plugin-index.ts b/server/lib/plugins/plugin-index.ts index 25b4f3c61..dcdfba28c 100644 --- a/server/lib/plugins/plugin-index.ts +++ b/server/lib/plugins/plugin-index.ts | |||
@@ -31,7 +31,7 @@ async function listAvailablePluginsFromIndex (options: PeertubePluginIndexList) | |||
31 | 31 | ||
32 | logger.debug('Got result from PeerTube index.', { body }) | 32 | logger.debug('Got result from PeerTube index.', { body }) |
33 | 33 | ||
34 | await addInstanceInformation(body) | 34 | addInstanceInformation(body) |
35 | 35 | ||
36 | return body as ResultList<PeerTubePluginIndex> | 36 | return body as ResultList<PeerTubePluginIndex> |
37 | } catch (err) { | 37 | } catch (err) { |
@@ -40,7 +40,7 @@ async function listAvailablePluginsFromIndex (options: PeertubePluginIndexList) | |||
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | async function addInstanceInformation (result: ResultList<PeerTubePluginIndex>) { | 43 | function addInstanceInformation (result: ResultList<PeerTubePluginIndex>) { |
44 | for (const d of result.data) { | 44 | for (const d of result.data) { |
45 | d.installed = PluginManager.Instance.isRegistered(d.npmName) | 45 | d.installed = PluginManager.Instance.isRegistered(d.npmName) |
46 | d.name = PluginModel.normalizePluginName(d.npmName) | 46 | d.name = PluginModel.normalizePluginName(d.npmName) |
diff --git a/server/lib/plugins/plugin-manager.ts b/server/lib/plugins/plugin-manager.ts index 7ebdabd34..73f7a71ce 100644 --- a/server/lib/plugins/plugin-manager.ts +++ b/server/lib/plugins/plugin-manager.ts | |||
@@ -55,30 +55,30 @@ export interface HookInformationValue { | |||
55 | } | 55 | } |
56 | 56 | ||
57 | type AlterableVideoConstant = 'language' | 'licence' | 'category' | 57 | type AlterableVideoConstant = 'language' | 'licence' | 'category' |
58 | type VideoConstant = { [ key in number | string ]: string } | 58 | type VideoConstant = { [key in number | string]: string } |
59 | type UpdatedVideoConstant = { | 59 | type UpdatedVideoConstant = { |
60 | [ name in AlterableVideoConstant ]: { | 60 | [name in AlterableVideoConstant]: { |
61 | [ npmName: string ]: { | 61 | [npmName: string]: { |
62 | added: { key: number | string, label: string }[], | 62 | added: { key: number | string, label: string }[] |
63 | deleted: { key: number | string, label: string }[] | 63 | deleted: { key: number | string, label: string }[] |
64 | } | 64 | } |
65 | } | 65 | } |
66 | } | 66 | } |
67 | 67 | ||
68 | type PluginLocalesTranslations = { | 68 | type PluginLocalesTranslations = { |
69 | [ locale: string ]: PluginTranslation | 69 | [locale: string]: PluginTranslation |
70 | } | 70 | } |
71 | 71 | ||
72 | export class PluginManager implements ServerHook { | 72 | export class PluginManager implements ServerHook { |
73 | 73 | ||
74 | private static instance: PluginManager | 74 | private static instance: PluginManager |
75 | 75 | ||
76 | private registeredPlugins: { [ name: string ]: RegisteredPlugin } = {} | 76 | private registeredPlugins: { [name: string]: RegisteredPlugin } = {} |
77 | private settings: { [ name: string ]: RegisterServerSettingOptions[] } = {} | 77 | private settings: { [name: string]: RegisterServerSettingOptions[] } = {} |
78 | private hooks: { [ name: string ]: HookInformationValue[] } = {} | 78 | private hooks: { [name: string]: HookInformationValue[] } = {} |
79 | private translations: PluginLocalesTranslations = {} | 79 | private translations: PluginLocalesTranslations = {} |
80 | 80 | ||
81 | private updatedVideoConstants: UpdatedVideoConstant = { | 81 | private readonly updatedVideoConstants: UpdatedVideoConstant = { |
82 | language: {}, | 82 | language: {}, |
83 | licence: {}, | 83 | licence: {}, |
84 | category: {} | 84 | category: {} |
@@ -133,7 +133,7 @@ export class PluginManager implements ServerHook { | |||
133 | 133 | ||
134 | // ###################### Hooks ###################### | 134 | // ###################### Hooks ###################### |
135 | 135 | ||
136 | async runHook <T> (hookName: ServerHookName, result?: T, params?: any): Promise<T> { | 136 | async runHook<T> (hookName: ServerHookName, result?: T, params?: any): Promise<T> { |
137 | if (!this.hooks[hookName]) return Promise.resolve(result) | 137 | if (!this.hooks[hookName]) return Promise.resolve(result) |
138 | 138 | ||
139 | const hookType = getHookType(hookName) | 139 | const hookType = getHookType(hookName) |
@@ -312,7 +312,7 @@ export class PluginManager implements ServerHook { | |||
312 | clientScripts[c.script] = c | 312 | clientScripts[c.script] = c |
313 | } | 313 | } |
314 | 314 | ||
315 | this.registeredPlugins[ npmName ] = { | 315 | this.registeredPlugins[npmName] = { |
316 | npmName, | 316 | npmName, |
317 | name: plugin.name, | 317 | name: plugin.name, |
318 | type: plugin.type, | 318 | type: plugin.type, |
@@ -438,7 +438,7 @@ export class PluginManager implements ServerHook { | |||
438 | const plugins: RegisteredPlugin[] = [] | 438 | const plugins: RegisteredPlugin[] = [] |
439 | 439 | ||
440 | for (const npmName of Object.keys(this.registeredPlugins)) { | 440 | for (const npmName of Object.keys(this.registeredPlugins)) { |
441 | const plugin = this.registeredPlugins[ npmName ] | 441 | const plugin = this.registeredPlugins[npmName] |
442 | if (plugin.type !== type) continue | 442 | if (plugin.type !== type) continue |
443 | 443 | ||
444 | plugins.push(plugin) | 444 | plugins.push(plugin) |
@@ -518,11 +518,11 @@ export class PluginManager implements ServerHook { | |||
518 | } | 518 | } |
519 | } | 519 | } |
520 | 520 | ||
521 | private addConstant <T extends string | number> (parameters: { | 521 | private addConstant<T extends string | number> (parameters: { |
522 | npmName: string, | 522 | npmName: string |
523 | type: AlterableVideoConstant, | 523 | type: AlterableVideoConstant |
524 | obj: VideoConstant, | 524 | obj: VideoConstant |
525 | key: T, | 525 | key: T |
526 | label: string | 526 | label: string |
527 | }) { | 527 | }) { |
528 | const { npmName, type, obj, key, label } = parameters | 528 | const { npmName, type, obj, key, label } = parameters |
@@ -545,10 +545,10 @@ export class PluginManager implements ServerHook { | |||
545 | return true | 545 | return true |
546 | } | 546 | } |
547 | 547 | ||
548 | private deleteConstant <T extends string | number> (parameters: { | 548 | private deleteConstant<T extends string | number> (parameters: { |
549 | npmName: string, | 549 | npmName: string |
550 | type: AlterableVideoConstant, | 550 | type: AlterableVideoConstant |
551 | obj: VideoConstant, | 551 | obj: VideoConstant |
552 | key: T | 552 | key: T |
553 | }) { | 553 | }) { |
554 | const { npmName, type, obj, key } = parameters | 554 | const { npmName, type, obj, key } = parameters |
@@ -604,7 +604,7 @@ export class PluginManager implements ServerHook { | |||
604 | const { result: packageJSONValid, badFields } = isPackageJSONValid(packageJSON, pluginType) | 604 | const { result: packageJSONValid, badFields } = isPackageJSONValid(packageJSON, pluginType) |
605 | if (!packageJSONValid) { | 605 | if (!packageJSONValid) { |
606 | const formattedFields = badFields.map(f => `"${f}"`) | 606 | const formattedFields = badFields.map(f => `"${f}"`) |
607 | .join(', ') | 607 | .join(', ') |
608 | 608 | ||
609 | throw new Error(`PackageJSON is invalid (invalid fields: ${formattedFields}).`) | 609 | throw new Error(`PackageJSON is invalid (invalid fields: ${formattedFields}).`) |
610 | } | 610 | } |
diff --git a/server/lib/redis.ts b/server/lib/redis.ts index f77d0b62c..0c5dbdd3e 100644 --- a/server/lib/redis.ts +++ b/server/lib/redis.ts | |||
@@ -12,7 +12,7 @@ import { | |||
12 | import { CONFIG } from '../initializers/config' | 12 | import { CONFIG } from '../initializers/config' |
13 | 13 | ||
14 | type CachedRoute = { | 14 | type CachedRoute = { |
15 | body: string, | 15 | body: string |
16 | contentType?: string | 16 | contentType?: string |
17 | statusCode?: string | 17 | statusCode?: string |
18 | } | 18 | } |
@@ -24,7 +24,8 @@ class Redis { | |||
24 | private client: RedisClient | 24 | private client: RedisClient |
25 | private prefix: string | 25 | private prefix: string |
26 | 26 | ||
27 | private constructor () {} | 27 | private constructor () { |
28 | } | ||
28 | 29 | ||
29 | init () { | 30 | init () { |
30 | // Already initialized | 31 | // Already initialized |
@@ -49,9 +50,9 @@ class Redis { | |||
49 | return Object.assign({}, | 50 | return Object.assign({}, |
50 | (CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {}, | 51 | (CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {}, |
51 | (CONFIG.REDIS.DB) ? { db: CONFIG.REDIS.DB } : {}, | 52 | (CONFIG.REDIS.DB) ? { db: CONFIG.REDIS.DB } : {}, |
52 | (CONFIG.REDIS.HOSTNAME && CONFIG.REDIS.PORT) ? | 53 | (CONFIG.REDIS.HOSTNAME && CONFIG.REDIS.PORT) |
53 | { host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT } : | 54 | ? { host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT } |
54 | { path: CONFIG.REDIS.SOCKET } | 55 | : { path: CONFIG.REDIS.SOCKET } |
55 | ) | 56 | ) |
56 | } | 57 | } |
57 | 58 | ||
@@ -63,7 +64,7 @@ class Redis { | |||
63 | return this.prefix | 64 | return this.prefix |
64 | } | 65 | } |
65 | 66 | ||
66 | /************* Forgot password *************/ | 67 | /* ************ Forgot password ************ */ |
67 | 68 | ||
68 | async setResetPasswordVerificationString (userId: number) { | 69 | async setResetPasswordVerificationString (userId: number) { |
69 | const generatedString = await generateRandomString(32) | 70 | const generatedString = await generateRandomString(32) |
@@ -77,7 +78,7 @@ class Redis { | |||
77 | return this.getValue(this.generateResetPasswordKey(userId)) | 78 | return this.getValue(this.generateResetPasswordKey(userId)) |
78 | } | 79 | } |
79 | 80 | ||
80 | /************* Email verification *************/ | 81 | /* ************ Email verification ************ */ |
81 | 82 | ||
82 | async setVerifyEmailVerificationString (userId: number) { | 83 | async setVerifyEmailVerificationString (userId: number) { |
83 | const generatedString = await generateRandomString(32) | 84 | const generatedString = await generateRandomString(32) |
@@ -91,7 +92,7 @@ class Redis { | |||
91 | return this.getValue(this.generateVerifyEmailKey(userId)) | 92 | return this.getValue(this.generateVerifyEmailKey(userId)) |
92 | } | 93 | } |
93 | 94 | ||
94 | /************* Contact form per IP *************/ | 95 | /* ************ Contact form per IP ************ */ |
95 | 96 | ||
96 | async setContactFormIp (ip: string) { | 97 | async setContactFormIp (ip: string) { |
97 | return this.setValue(this.generateContactFormKey(ip), '1', CONTACT_FORM_LIFETIME) | 98 | return this.setValue(this.generateContactFormKey(ip), '1', CONTACT_FORM_LIFETIME) |
@@ -101,7 +102,7 @@ class Redis { | |||
101 | return this.exists(this.generateContactFormKey(ip)) | 102 | return this.exists(this.generateContactFormKey(ip)) |
102 | } | 103 | } |
103 | 104 | ||
104 | /************* Views per IP *************/ | 105 | /* ************ Views per IP ************ */ |
105 | 106 | ||
106 | setIPVideoView (ip: string, videoUUID: string) { | 107 | setIPVideoView (ip: string, videoUUID: string) { |
107 | return this.setValue(this.generateViewKey(ip, videoUUID), '1', VIDEO_VIEW_LIFETIME) | 108 | return this.setValue(this.generateViewKey(ip, videoUUID), '1', VIDEO_VIEW_LIFETIME) |
@@ -111,7 +112,7 @@ class Redis { | |||
111 | return this.exists(this.generateViewKey(ip, videoUUID)) | 112 | return this.exists(this.generateViewKey(ip, videoUUID)) |
112 | } | 113 | } |
113 | 114 | ||
114 | /************* API cache *************/ | 115 | /* ************ API cache ************ */ |
115 | 116 | ||
116 | async getCachedRoute (req: express.Request) { | 117 | async getCachedRoute (req: express.Request) { |
117 | const cached = await this.getObject(this.generateCachedRouteKey(req)) | 118 | const cached = await this.getObject(this.generateCachedRouteKey(req)) |
@@ -120,17 +121,17 @@ class Redis { | |||
120 | } | 121 | } |
121 | 122 | ||
122 | setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) { | 123 | setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) { |
123 | const cached: CachedRoute = Object.assign({}, { | 124 | const cached: CachedRoute = Object.assign( |
124 | body: body.toString() | 125 | {}, |
125 | }, | 126 | { body: body.toString() }, |
126 | (contentType) ? { contentType } : null, | 127 | (contentType) ? { contentType } : null, |
127 | (statusCode) ? { statusCode: statusCode.toString() } : null | 128 | (statusCode) ? { statusCode: statusCode.toString() } : null |
128 | ) | 129 | ) |
129 | 130 | ||
130 | return this.setObject(this.generateCachedRouteKey(req), cached, lifetime) | 131 | return this.setObject(this.generateCachedRouteKey(req), cached, lifetime) |
131 | } | 132 | } |
132 | 133 | ||
133 | /************* Video views *************/ | 134 | /* ************ Video views ************ */ |
134 | 135 | ||
135 | addVideoView (videoId: number) { | 136 | addVideoView (videoId: number) { |
136 | const keyIncr = this.generateVideoViewKey(videoId) | 137 | const keyIncr = this.generateVideoViewKey(videoId) |
@@ -173,7 +174,7 @@ class Redis { | |||
173 | ]) | 174 | ]) |
174 | } | 175 | } |
175 | 176 | ||
176 | /************* Keys generation *************/ | 177 | /* ************ Keys generation ************ */ |
177 | 178 | ||
178 | generateCachedRouteKey (req: express.Request) { | 179 | generateCachedRouteKey (req: express.Request) { |
179 | return req.method + '-' + req.originalUrl | 180 | return req.method + '-' + req.originalUrl |
@@ -207,7 +208,7 @@ class Redis { | |||
207 | return 'contact-form-' + ip | 208 | return 'contact-form-' + ip |
208 | } | 209 | } |
209 | 210 | ||
210 | /************* Redis helpers *************/ | 211 | /* ************ Redis helpers ************ */ |
211 | 212 | ||
212 | private getValue (key: string) { | 213 | private getValue (key: string) { |
213 | return new Promise<string>((res, rej) => { | 214 | return new Promise<string>((res, rej) => { |
@@ -265,7 +266,7 @@ class Redis { | |||
265 | }) | 266 | }) |
266 | } | 267 | } |
267 | 268 | ||
268 | private setObject (key: string, obj: { [ id: string ]: string }, expirationMilliseconds: number) { | 269 | private setObject (key: string, obj: { [id: string]: string }, expirationMilliseconds: number) { |
269 | return new Promise<void>((res, rej) => { | 270 | return new Promise<void>((res, rej) => { |
270 | this.client.hmset(this.prefix + key, obj, (err, ok) => { | 271 | this.client.hmset(this.prefix + key, obj, (err, ok) => { |
271 | if (err) return rej(err) | 272 | if (err) return rej(err) |
@@ -282,7 +283,7 @@ class Redis { | |||
282 | } | 283 | } |
283 | 284 | ||
284 | private getObject (key: string) { | 285 | private getObject (key: string) { |
285 | return new Promise<{ [ id: string ]: string }>((res, rej) => { | 286 | return new Promise<{ [id: string]: string }>((res, rej) => { |
286 | this.client.hgetall(this.prefix + key, (err, value) => { | 287 | this.client.hgetall(this.prefix + key, (err, value) => { |
287 | if (err) return rej(err) | 288 | if (err) return rej(err) |
288 | 289 | ||
diff --git a/server/lib/redundancy.ts b/server/lib/redundancy.ts index 1b4ecd7c0..78d84e02e 100644 --- a/server/lib/redundancy.ts +++ b/server/lib/redundancy.ts | |||
@@ -13,10 +13,10 @@ async function removeVideoRedundancy (videoRedundancy: MVideoRedundancyVideo, t? | |||
13 | await videoRedundancy.destroy({ transaction: t }) | 13 | await videoRedundancy.destroy({ transaction: t }) |
14 | } | 14 | } |
15 | 15 | ||
16 | async function removeRedundancyOf (serverId: number) { | 16 | async function removeRedundanciesOfServer (serverId: number) { |
17 | const videosRedundancy = await VideoRedundancyModel.listLocalOfServer(serverId) | 17 | const redundancies = await VideoRedundancyModel.listLocalOfServer(serverId) |
18 | 18 | ||
19 | for (const redundancy of videosRedundancy) { | 19 | for (const redundancy of redundancies) { |
20 | await removeVideoRedundancy(redundancy) | 20 | await removeVideoRedundancy(redundancy) |
21 | } | 21 | } |
22 | } | 22 | } |
@@ -24,6 +24,6 @@ async function removeRedundancyOf (serverId: number) { | |||
24 | // --------------------------------------------------------------------------- | 24 | // --------------------------------------------------------------------------- |
25 | 25 | ||
26 | export { | 26 | export { |
27 | removeRedundancyOf, | 27 | removeRedundanciesOfServer, |
28 | removeVideoRedundancy | 28 | removeVideoRedundancy |
29 | } | 29 | } |
diff --git a/server/lib/schedulers/auto-follow-index-instances.ts b/server/lib/schedulers/auto-follow-index-instances.ts index dd326bc1e..d700a99f0 100644 --- a/server/lib/schedulers/auto-follow-index-instances.ts +++ b/server/lib/schedulers/auto-follow-index-instances.ts | |||
@@ -57,8 +57,7 @@ export class AutoFollowIndexInstances extends AbstractScheduler { | |||
57 | isAutoFollow: true | 57 | isAutoFollow: true |
58 | } | 58 | } |
59 | 59 | ||
60 | await JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) | 60 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) |
61 | .catch(err => logger.error('Cannot create follow job for %s.', unfollowedHost, err)) | ||
62 | } | 61 | } |
63 | } | 62 | } |
64 | 63 | ||
diff --git a/server/lib/schedulers/plugins-check-scheduler.ts b/server/lib/schedulers/plugins-check-scheduler.ts index 7ff41e639..014993e94 100644 --- a/server/lib/schedulers/plugins-check-scheduler.ts +++ b/server/lib/schedulers/plugins-check-scheduler.ts | |||
@@ -43,7 +43,7 @@ export class PluginsCheckScheduler extends AbstractScheduler { | |||
43 | const results = await getLatestPluginsVersion(npmNames) | 43 | const results = await getLatestPluginsVersion(npmNames) |
44 | 44 | ||
45 | for (const result of results) { | 45 | for (const result of results) { |
46 | const plugin = pluginIndex[ result.npmName ] | 46 | const plugin = pluginIndex[result.npmName] |
47 | if (!result.latestVersion) continue | 47 | if (!result.latestVersion) continue |
48 | 48 | ||
49 | if ( | 49 | if ( |
diff --git a/server/lib/schedulers/remove-old-views-scheduler.ts b/server/lib/schedulers/remove-old-views-scheduler.ts index 39fbb9163..5ae87fe50 100644 --- a/server/lib/schedulers/remove-old-views-scheduler.ts +++ b/server/lib/schedulers/remove-old-views-scheduler.ts | |||
@@ -1,9 +1,7 @@ | |||
1 | import { logger } from '../../helpers/logger' | 1 | import { logger } from '../../helpers/logger' |
2 | import { AbstractScheduler } from './abstract-scheduler' | 2 | import { AbstractScheduler } from './abstract-scheduler' |
3 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' | 3 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' |
4 | import { UserVideoHistoryModel } from '../../models/account/user-video-history' | ||
5 | import { CONFIG } from '../../initializers/config' | 4 | import { CONFIG } from '../../initializers/config' |
6 | import { isTestInstance } from '../../helpers/core-utils' | ||
7 | import { VideoViewModel } from '../../models/video/video-views' | 5 | import { VideoViewModel } from '../../models/video/video-views' |
8 | 6 | ||
9 | export class RemoveOldViewsScheduler extends AbstractScheduler { | 7 | export class RemoveOldViewsScheduler extends AbstractScheduler { |
diff --git a/server/lib/schedulers/update-videos-scheduler.ts b/server/lib/schedulers/update-videos-scheduler.ts index 350a335d3..956780a77 100644 --- a/server/lib/schedulers/update-videos-scheduler.ts +++ b/server/lib/schedulers/update-videos-scheduler.ts | |||
@@ -4,7 +4,6 @@ import { ScheduleVideoUpdateModel } from '../../models/video/schedule-video-upda | |||
4 | import { retryTransactionWrapper } from '../../helpers/database-utils' | 4 | import { retryTransactionWrapper } from '../../helpers/database-utils' |
5 | import { federateVideoIfNeeded } from '../activitypub' | 5 | import { federateVideoIfNeeded } from '../activitypub' |
6 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' | 6 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' |
7 | import { VideoPrivacy } from '../../../shared/models/videos' | ||
8 | import { Notifier } from '../notifier' | 7 | import { Notifier } from '../notifier' |
9 | import { sequelizeTypescript } from '../../initializers/database' | 8 | import { sequelizeTypescript } from '../../initializers/database' |
10 | import { MVideoFullLight } from '@server/typings/models' | 9 | import { MVideoFullLight } from '@server/typings/models' |
diff --git a/server/lib/schedulers/videos-redundancy-scheduler.ts b/server/lib/schedulers/videos-redundancy-scheduler.ts index c1c91b656..e33a4133a 100644 --- a/server/lib/schedulers/videos-redundancy-scheduler.ts +++ b/server/lib/schedulers/videos-redundancy-scheduler.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { AbstractScheduler } from './abstract-scheduler' | 1 | import { AbstractScheduler } from './abstract-scheduler' |
2 | import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT, WEBSERVER } from '../../initializers/constants' | 2 | import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT, WEBSERVER } from '../../initializers/constants' |
3 | import { logger } from '../../helpers/logger' | 3 | import { logger } from '../../helpers/logger' |
4 | import { VideosRedundancy } from '../../../shared/models/redundancy' | 4 | import { VideosRedundancyStrategy } from '../../../shared/models/redundancy' |
5 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' | 5 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' |
6 | import { downloadWebTorrentVideo, generateMagnetUri } from '../../helpers/webtorrent' | 6 | import { downloadWebTorrentVideo, generateMagnetUri } from '../../helpers/webtorrent' |
7 | import { join } from 'path' | 7 | import { join } from 'path' |
@@ -25,11 +25,12 @@ import { | |||
25 | MVideoWithAllFiles | 25 | MVideoWithAllFiles |
26 | } from '@server/typings/models' | 26 | } from '@server/typings/models' |
27 | import { getVideoFilename } from '../video-paths' | 27 | import { getVideoFilename } from '../video-paths' |
28 | import { VideoModel } from '@server/models/video/video' | ||
28 | 29 | ||
29 | type CandidateToDuplicate = { | 30 | type CandidateToDuplicate = { |
30 | redundancy: VideosRedundancy, | 31 | redundancy: VideosRedundancyStrategy |
31 | video: MVideoWithAllFiles, | 32 | video: MVideoWithAllFiles |
32 | files: MVideoFile[], | 33 | files: MVideoFile[] |
33 | streamingPlaylists: MStreamingPlaylistFiles[] | 34 | streamingPlaylists: MStreamingPlaylistFiles[] |
34 | } | 35 | } |
35 | 36 | ||
@@ -41,7 +42,7 @@ function isMVideoRedundancyFileVideo ( | |||
41 | 42 | ||
42 | export class VideosRedundancyScheduler extends AbstractScheduler { | 43 | export class VideosRedundancyScheduler extends AbstractScheduler { |
43 | 44 | ||
44 | private static instance: AbstractScheduler | 45 | private static instance: VideosRedundancyScheduler |
45 | 46 | ||
46 | protected schedulerIntervalMs = CONFIG.REDUNDANCY.VIDEOS.CHECK_INTERVAL | 47 | protected schedulerIntervalMs = CONFIG.REDUNDANCY.VIDEOS.CHECK_INTERVAL |
47 | 48 | ||
@@ -49,6 +50,22 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
49 | super() | 50 | super() |
50 | } | 51 | } |
51 | 52 | ||
53 | async createManualRedundancy (videoId: number) { | ||
54 | const videoToDuplicate = await VideoModel.loadWithFiles(videoId) | ||
55 | |||
56 | if (!videoToDuplicate) { | ||
57 | logger.warn('Video to manually duplicate %d does not exist anymore.', videoId) | ||
58 | return | ||
59 | } | ||
60 | |||
61 | return this.createVideoRedundancies({ | ||
62 | video: videoToDuplicate, | ||
63 | redundancy: null, | ||
64 | files: videoToDuplicate.VideoFiles, | ||
65 | streamingPlaylists: videoToDuplicate.VideoStreamingPlaylists | ||
66 | }) | ||
67 | } | ||
68 | |||
52 | protected async internalExecute () { | 69 | protected async internalExecute () { |
53 | for (const redundancyConfig of CONFIG.REDUNDANCY.VIDEOS.STRATEGIES) { | 70 | for (const redundancyConfig of CONFIG.REDUNDANCY.VIDEOS.STRATEGIES) { |
54 | logger.info('Running redundancy scheduler for strategy %s.', redundancyConfig.strategy) | 71 | logger.info('Running redundancy scheduler for strategy %s.', redundancyConfig.strategy) |
@@ -94,7 +111,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
94 | for (const redundancyModel of expired) { | 111 | for (const redundancyModel of expired) { |
95 | try { | 112 | try { |
96 | const redundancyConfig = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.find(s => s.strategy === redundancyModel.strategy) | 113 | const redundancyConfig = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.find(s => s.strategy === redundancyModel.strategy) |
97 | const candidate = { | 114 | const candidate: CandidateToDuplicate = { |
98 | redundancy: redundancyConfig, | 115 | redundancy: redundancyConfig, |
99 | video: null, | 116 | video: null, |
100 | files: [], | 117 | files: [], |
@@ -140,7 +157,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
140 | } | 157 | } |
141 | } | 158 | } |
142 | 159 | ||
143 | private findVideoToDuplicate (cache: VideosRedundancy) { | 160 | private findVideoToDuplicate (cache: VideosRedundancyStrategy) { |
144 | if (cache.strategy === 'most-views') { | 161 | if (cache.strategy === 'most-views') { |
145 | return VideoRedundancyModel.findMostViewToDuplicate(REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR) | 162 | return VideoRedundancyModel.findMostViewToDuplicate(REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR) |
146 | } | 163 | } |
@@ -187,13 +204,21 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
187 | } | 204 | } |
188 | } | 205 | } |
189 | 206 | ||
190 | private async createVideoFileRedundancy (redundancy: VideosRedundancy, video: MVideoAccountLight, fileArg: MVideoFile) { | 207 | private async createVideoFileRedundancy (redundancy: VideosRedundancyStrategy | null, video: MVideoAccountLight, fileArg: MVideoFile) { |
208 | let strategy = 'manual' | ||
209 | let expiresOn: Date = null | ||
210 | |||
211 | if (redundancy) { | ||
212 | strategy = redundancy.strategy | ||
213 | expiresOn = this.buildNewExpiration(redundancy.minLifetime) | ||
214 | } | ||
215 | |||
191 | const file = fileArg as MVideoFileVideo | 216 | const file = fileArg as MVideoFileVideo |
192 | file.Video = video | 217 | file.Video = video |
193 | 218 | ||
194 | const serverActor = await getServerActor() | 219 | const serverActor = await getServerActor() |
195 | 220 | ||
196 | logger.info('Duplicating %s - %d in videos redundancy with "%s" strategy.', video.url, file.resolution, redundancy.strategy) | 221 | logger.info('Duplicating %s - %d in videos redundancy with "%s" strategy.', video.url, file.resolution, strategy) |
197 | 222 | ||
198 | const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() | 223 | const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() |
199 | const magnetUri = generateMagnetUri(video, file, baseUrlHttp, baseUrlWs) | 224 | const magnetUri = generateMagnetUri(video, file, baseUrlHttp, baseUrlWs) |
@@ -204,10 +229,10 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
204 | await move(tmpPath, destPath, { overwrite: true }) | 229 | await move(tmpPath, destPath, { overwrite: true }) |
205 | 230 | ||
206 | const createdModel: MVideoRedundancyFileVideo = await VideoRedundancyModel.create({ | 231 | const createdModel: MVideoRedundancyFileVideo = await VideoRedundancyModel.create({ |
207 | expiresOn: this.buildNewExpiration(redundancy.minLifetime), | 232 | expiresOn, |
208 | url: getVideoCacheFileActivityPubUrl(file), | 233 | url: getVideoCacheFileActivityPubUrl(file), |
209 | fileUrl: video.getVideoRedundancyUrl(file, WEBSERVER.URL), | 234 | fileUrl: video.getVideoRedundancyUrl(file, WEBSERVER.URL), |
210 | strategy: redundancy.strategy, | 235 | strategy, |
211 | videoFileId: file.id, | 236 | videoFileId: file.id, |
212 | actorId: serverActor.id | 237 | actorId: serverActor.id |
213 | }) | 238 | }) |
@@ -220,25 +245,33 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
220 | } | 245 | } |
221 | 246 | ||
222 | private async createStreamingPlaylistRedundancy ( | 247 | private async createStreamingPlaylistRedundancy ( |
223 | redundancy: VideosRedundancy, | 248 | redundancy: VideosRedundancyStrategy, |
224 | video: MVideoAccountLight, | 249 | video: MVideoAccountLight, |
225 | playlistArg: MStreamingPlaylist | 250 | playlistArg: MStreamingPlaylist |
226 | ) { | 251 | ) { |
252 | let strategy = 'manual' | ||
253 | let expiresOn: Date = null | ||
254 | |||
255 | if (redundancy) { | ||
256 | strategy = redundancy.strategy | ||
257 | expiresOn = this.buildNewExpiration(redundancy.minLifetime) | ||
258 | } | ||
259 | |||
227 | const playlist = playlistArg as MStreamingPlaylistVideo | 260 | const playlist = playlistArg as MStreamingPlaylistVideo |
228 | playlist.Video = video | 261 | playlist.Video = video |
229 | 262 | ||
230 | const serverActor = await getServerActor() | 263 | const serverActor = await getServerActor() |
231 | 264 | ||
232 | logger.info('Duplicating %s streaming playlist in videos redundancy with "%s" strategy.', video.url, redundancy.strategy) | 265 | logger.info('Duplicating %s streaming playlist in videos redundancy with "%s" strategy.', video.url, strategy) |
233 | 266 | ||
234 | const destDirectory = join(HLS_REDUNDANCY_DIRECTORY, video.uuid) | 267 | const destDirectory = join(HLS_REDUNDANCY_DIRECTORY, video.uuid) |
235 | await downloadPlaylistSegments(playlist.playlistUrl, destDirectory, VIDEO_IMPORT_TIMEOUT) | 268 | await downloadPlaylistSegments(playlist.playlistUrl, destDirectory, VIDEO_IMPORT_TIMEOUT) |
236 | 269 | ||
237 | const createdModel: MVideoRedundancyStreamingPlaylistVideo = await VideoRedundancyModel.create({ | 270 | const createdModel: MVideoRedundancyStreamingPlaylistVideo = await VideoRedundancyModel.create({ |
238 | expiresOn: this.buildNewExpiration(redundancy.minLifetime), | 271 | expiresOn, |
239 | url: getVideoCacheStreamingPlaylistActivityPubUrl(video, playlist), | 272 | url: getVideoCacheStreamingPlaylistActivityPubUrl(video, playlist), |
240 | fileUrl: playlist.getVideoRedundancyUrl(WEBSERVER.URL), | 273 | fileUrl: playlist.getVideoRedundancyUrl(WEBSERVER.URL), |
241 | strategy: redundancy.strategy, | 274 | strategy, |
242 | videoStreamingPlaylistId: playlist.id, | 275 | videoStreamingPlaylistId: playlist.id, |
243 | actorId: serverActor.id | 276 | actorId: serverActor.id |
244 | }) | 277 | }) |
diff --git a/server/lib/thumbnail.ts b/server/lib/thumbnail.ts index a99f71629..8dbd41771 100644 --- a/server/lib/thumbnail.ts +++ b/server/lib/thumbnail.ts | |||
@@ -69,7 +69,7 @@ function generateVideoMiniature (video: MVideoThumbnail, videoFile: MVideoFile, | |||
69 | function createPlaceholderThumbnail (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size: ImageSize) { | 69 | function createPlaceholderThumbnail (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size: ImageSize) { |
70 | const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) | 70 | const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) |
71 | 71 | ||
72 | const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel() | 72 | const thumbnail = existingThumbnail || new ThumbnailModel() |
73 | 73 | ||
74 | thumbnail.filename = filename | 74 | thumbnail.filename = filename |
75 | thumbnail.height = height | 75 | thumbnail.height = height |
@@ -142,18 +142,18 @@ function buildMetadataFromVideo (video: MVideoThumbnail, type: ThumbnailType, si | |||
142 | } | 142 | } |
143 | 143 | ||
144 | async function createThumbnailFromFunction (parameters: { | 144 | async function createThumbnailFromFunction (parameters: { |
145 | thumbnailCreator: () => Promise<any>, | 145 | thumbnailCreator: () => Promise<any> |
146 | filename: string, | 146 | filename: string |
147 | height: number, | 147 | height: number |
148 | width: number, | 148 | width: number |
149 | type: ThumbnailType, | 149 | type: ThumbnailType |
150 | automaticallyGenerated?: boolean, | 150 | automaticallyGenerated?: boolean |
151 | fileUrl?: string, | 151 | fileUrl?: string |
152 | existingThumbnail?: MThumbnail | 152 | existingThumbnail?: MThumbnail |
153 | }) { | 153 | }) { |
154 | const { thumbnailCreator, filename, width, height, type, existingThumbnail, automaticallyGenerated = null, fileUrl = null } = parameters | 154 | const { thumbnailCreator, filename, width, height, type, existingThumbnail, automaticallyGenerated = null, fileUrl = null } = parameters |
155 | 155 | ||
156 | const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel() | 156 | const thumbnail = existingThumbnail || new ThumbnailModel() |
157 | 157 | ||
158 | thumbnail.filename = filename | 158 | thumbnail.filename = filename |
159 | thumbnail.height = height | 159 | thumbnail.height = height |
diff --git a/server/lib/user.ts b/server/lib/user.ts index c45438d95..88e60a7df 100644 --- a/server/lib/user.ts +++ b/server/lib/user.ts | |||
@@ -18,9 +18,9 @@ import { MUser, MUserDefault, MUserId } from '../typings/models/user' | |||
18 | type ChannelNames = { name: string, displayName: string } | 18 | type ChannelNames = { name: string, displayName: string } |
19 | 19 | ||
20 | async function createUserAccountAndChannelAndPlaylist (parameters: { | 20 | async function createUserAccountAndChannelAndPlaylist (parameters: { |
21 | userToCreate: MUser, | 21 | userToCreate: MUser |
22 | userDisplayName?: string, | 22 | userDisplayName?: string |
23 | channelNames?: ChannelNames, | 23 | channelNames?: ChannelNames |
24 | validateUser?: boolean | 24 | validateUser?: boolean |
25 | }): Promise<{ user: MUserDefault, account: MAccountDefault, videoChannel: MChannelActor }> { | 25 | }): Promise<{ user: MUserDefault, account: MAccountDefault, videoChannel: MChannelActor }> { |
26 | const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters | 26 | const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters |
@@ -63,11 +63,11 @@ async function createUserAccountAndChannelAndPlaylist (parameters: { | |||
63 | } | 63 | } |
64 | 64 | ||
65 | async function createLocalAccountWithoutKeys (parameters: { | 65 | async function createLocalAccountWithoutKeys (parameters: { |
66 | name: string, | 66 | name: string |
67 | displayName?: string, | 67 | displayName?: string |
68 | userId: number | null, | 68 | userId: number | null |
69 | applicationId: number | null, | 69 | applicationId: number | null |
70 | t: Transaction | undefined, | 70 | t: Transaction | undefined |
71 | type?: ActivityPubActorType | 71 | type?: ActivityPubActorType |
72 | }) { | 72 | }) { |
73 | const { name, displayName, userId, applicationId, t, type = 'Person' } = parameters | 73 | const { name, displayName, userId, applicationId, t, type = 'Person' } = parameters |
diff --git a/server/lib/video-blacklist.ts b/server/lib/video-blacklist.ts index 1dd45b76d..3b90b1b94 100644 --- a/server/lib/video-blacklist.ts +++ b/server/lib/video-blacklist.ts | |||
@@ -9,15 +9,15 @@ import { Notifier } from './notifier' | |||
9 | import { MUser, MVideoBlacklistVideo, MVideoWithBlacklistLight } from '@server/typings/models' | 9 | import { MUser, MVideoBlacklistVideo, MVideoWithBlacklistLight } from '@server/typings/models' |
10 | 10 | ||
11 | async function autoBlacklistVideoIfNeeded (parameters: { | 11 | async function autoBlacklistVideoIfNeeded (parameters: { |
12 | video: MVideoWithBlacklistLight, | 12 | video: MVideoWithBlacklistLight |
13 | user?: MUser, | 13 | user?: MUser |
14 | isRemote: boolean, | 14 | isRemote: boolean |
15 | isNew: boolean, | 15 | isNew: boolean |
16 | notify?: boolean, | 16 | notify?: boolean |
17 | transaction?: Transaction | 17 | transaction?: Transaction |
18 | }) { | 18 | }) { |
19 | const { video, user, isRemote, isNew, notify = true, transaction } = parameters | 19 | const { video, user, isRemote, isNew, notify = true, transaction } = parameters |
20 | const doAutoBlacklist = await Hooks.wrapPromiseFun( | 20 | const doAutoBlacklist = await Hooks.wrapFun( |
21 | autoBlacklistNeeded, | 21 | autoBlacklistNeeded, |
22 | { video, user, isRemote, isNew }, | 22 | { video, user, isRemote, isNew }, |
23 | 'filter:video.auto-blacklist.result' | 23 | 'filter:video.auto-blacklist.result' |
@@ -49,10 +49,10 @@ async function autoBlacklistVideoIfNeeded (parameters: { | |||
49 | return true | 49 | return true |
50 | } | 50 | } |
51 | 51 | ||
52 | async function autoBlacklistNeeded (parameters: { | 52 | function autoBlacklistNeeded (parameters: { |
53 | video: MVideoWithBlacklistLight, | 53 | video: MVideoWithBlacklistLight |
54 | isRemote: boolean, | 54 | isRemote: boolean |
55 | isNew: boolean, | 55 | isNew: boolean |
56 | user?: MUser | 56 | user?: MUser |
57 | }) { | 57 | }) { |
58 | const { user, video, isRemote, isNew } = parameters | 58 | const { user, video, isRemote, isNew } = parameters |
diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts index 41eab456b..14829c9d6 100644 --- a/server/lib/video-channel.ts +++ b/server/lib/video-channel.ts | |||
@@ -6,8 +6,7 @@ import { buildActorInstance, federateVideoIfNeeded, getVideoChannelActivityPubUr | |||
6 | import { VideoModel } from '../models/video/video' | 6 | import { VideoModel } from '../models/video/video' |
7 | import { MAccountId, MChannelDefault, MChannelId } from '../typings/models' | 7 | import { MAccountId, MChannelDefault, MChannelId } from '../typings/models' |
8 | 8 | ||
9 | type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelDefault & | 9 | type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelDefault & { Account?: T } |
10 | { Account?: T } | ||
11 | 10 | ||
12 | async function createLocalVideoChannel <T extends MAccountId> ( | 11 | async function createLocalVideoChannel <T extends MAccountId> ( |
13 | videoChannelInfo: VideoChannelCreate, | 12 | videoChannelInfo: VideoChannelCreate, |
diff --git a/server/lib/video-comment.ts b/server/lib/video-comment.ts index b8074e6d2..fe83d23e7 100644 --- a/server/lib/video-comment.ts +++ b/server/lib/video-comment.ts | |||
@@ -7,9 +7,9 @@ import { sendCreateVideoComment } from './activitypub/send' | |||
7 | import { MAccountDefault, MComment, MCommentOwnerVideoReply, MVideoFullLight } from '../typings/models' | 7 | import { MAccountDefault, MComment, MCommentOwnerVideoReply, MVideoFullLight } from '../typings/models' |
8 | 8 | ||
9 | async function createVideoComment (obj: { | 9 | async function createVideoComment (obj: { |
10 | text: string, | 10 | text: string |
11 | inReplyToComment: MComment | null, | 11 | inReplyToComment: MComment | null |
12 | video: MVideoFullLight, | 12 | video: MVideoFullLight |
13 | account: MAccountDefault | 13 | account: MAccountDefault |
14 | }, t: Sequelize.Transaction) { | 14 | }, t: Sequelize.Transaction) { |
15 | let originCommentId: number | null = null | 15 | let originCommentId: number | null = null |
diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts index c6d8466ac..ab7d04d25 100644 --- a/server/middlewares/activitypub.ts +++ b/server/middlewares/activitypub.ts | |||
@@ -1,10 +1,12 @@ | |||
1 | import { NextFunction, Request, Response } from 'express' | 1 | import { NextFunction, Request, Response } from 'express' |
2 | import { ActivityPubSignature } from '../../shared' | 2 | import { ActivityDelete, ActivityPubSignature } from '../../shared' |
3 | import { logger } from '../helpers/logger' | 3 | import { logger } from '../helpers/logger' |
4 | import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' | 4 | import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' |
5 | import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers/constants' | 5 | import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers/constants' |
6 | import { getOrCreateActorAndServerAndModel } from '../lib/activitypub' | 6 | import { getOrCreateActorAndServerAndModel } from '../lib/activitypub' |
7 | import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger' | 7 | import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger' |
8 | import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor' | ||
9 | import { getAPId } from '@server/helpers/activitypub' | ||
8 | 10 | ||
9 | async function checkSignature (req: Request, res: Response, next: NextFunction) { | 11 | async function checkSignature (req: Request, res: Response, next: NextFunction) { |
10 | try { | 12 | try { |
@@ -15,7 +17,7 @@ async function checkSignature (req: Request, res: Response, next: NextFunction) | |||
15 | 17 | ||
16 | // Forwarded activity | 18 | // Forwarded activity |
17 | const bodyActor = req.body.actor | 19 | const bodyActor = req.body.actor |
18 | const bodyActorId = bodyActor && bodyActor.id ? bodyActor.id : bodyActor | 20 | const bodyActorId = getAPId(bodyActor) |
19 | if (bodyActorId && bodyActorId !== actor.url) { | 21 | if (bodyActorId && bodyActorId !== actor.url) { |
20 | const jsonLDSignatureChecked = await checkJsonLDSignature(req, res) | 22 | const jsonLDSignatureChecked = await checkJsonLDSignature(req, res) |
21 | if (jsonLDSignatureChecked !== true) return | 23 | if (jsonLDSignatureChecked !== true) return |
@@ -23,7 +25,13 @@ async function checkSignature (req: Request, res: Response, next: NextFunction) | |||
23 | 25 | ||
24 | return next() | 26 | return next() |
25 | } catch (err) { | 27 | } catch (err) { |
26 | logger.error('Error in ActivityPub signature checker.', err) | 28 | const activity: ActivityDelete = req.body |
29 | if (isActorDeleteActivityValid(activity) && activity.object === activity.actor) { | ||
30 | logger.debug('Handling signature error on actor delete activity', { err }) | ||
31 | return res.sendStatus(204) | ||
32 | } | ||
33 | |||
34 | logger.warn('Error in ActivityPub signature checker.', { err }) | ||
27 | return res.sendStatus(403) | 35 | return res.sendStatus(403) |
28 | } | 36 | } |
29 | } | 37 | } |
diff --git a/server/middlewares/csp.ts b/server/middlewares/csp.ts index d11d70790..f5de69603 100644 --- a/server/middlewares/csp.ts +++ b/server/middlewares/csp.ts | |||
@@ -3,20 +3,20 @@ import { CONFIG } from '../initializers/config' | |||
3 | 3 | ||
4 | const baseDirectives = Object.assign({}, | 4 | const baseDirectives = Object.assign({}, |
5 | { | 5 | { |
6 | defaultSrc: ["'none'"], // by default, not specifying default-src = '*' | 6 | defaultSrc: [ '\'none\'' ], // by default, not specifying default-src = '*' |
7 | connectSrc: ['*', 'data:'], | 7 | connectSrc: [ '*', 'data:' ], |
8 | mediaSrc: ["'self'", 'https:', 'blob:'], | 8 | mediaSrc: [ '\'self\'', 'https:', 'blob:' ], |
9 | fontSrc: ["'self'", 'data:'], | 9 | fontSrc: [ '\'self\'', 'data:' ], |
10 | imgSrc: ["'self'", 'data:', 'blob:'], | 10 | imgSrc: [ '\'self\'', 'data:', 'blob:' ], |
11 | scriptSrc: ["'self' 'unsafe-inline' 'unsafe-eval'", 'blob:'], | 11 | scriptSrc: [ '\'self\' \'unsafe-inline\' \'unsafe-eval\'', 'blob:' ], |
12 | styleSrc: ["'self' 'unsafe-inline'"], | 12 | styleSrc: [ '\'self\' \'unsafe-inline\'' ], |
13 | objectSrc: ["'none'"], // only define to allow plugins, else let defaultSrc 'none' block it | 13 | objectSrc: [ '\'none\'' ], // only define to allow plugins, else let defaultSrc 'none' block it |
14 | formAction: ["'self'"], | 14 | formAction: [ '\'self\'' ], |
15 | frameAncestors: ["'none'"], | 15 | frameAncestors: [ '\'none\'' ], |
16 | baseUri: ["'self'"], | 16 | baseUri: [ '\'self\'' ], |
17 | manifestSrc: ["'self'"], | 17 | manifestSrc: [ '\'self\'' ], |
18 | frameSrc: ["'self'"], // instead of deprecated child-src / self because of test-embed | 18 | frameSrc: [ '\'self\'' ], // instead of deprecated child-src / self because of test-embed |
19 | workerSrc: ["'self'", 'blob:'] // instead of deprecated child-src | 19 | workerSrc: [ '\'self\'', 'blob:' ] // instead of deprecated child-src |
20 | }, | 20 | }, |
21 | CONFIG.CSP.REPORT_URI ? { reportUri: CONFIG.CSP.REPORT_URI } : {}, | 21 | CONFIG.CSP.REPORT_URI ? { reportUri: CONFIG.CSP.REPORT_URI } : {}, |
22 | CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {} | 22 | CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {} |
@@ -29,7 +29,7 @@ const baseCSP = helmet.contentSecurityPolicy({ | |||
29 | }) | 29 | }) |
30 | 30 | ||
31 | const embedCSP = helmet.contentSecurityPolicy({ | 31 | const embedCSP = helmet.contentSecurityPolicy({ |
32 | directives: Object.assign({}, baseDirectives, { frameAncestors: ['*'] }), | 32 | directives: Object.assign({}, baseDirectives, { frameAncestors: [ '*' ] }), |
33 | browserSniff: false, // assumes a modern browser, but allows CDN in front | 33 | browserSniff: false, // assumes a modern browser, but allows CDN in front |
34 | reportOnly: CONFIG.CSP.REPORT_ONLY | 34 | reportOnly: CONFIG.CSP.REPORT_ONLY |
35 | }) | 35 | }) |
diff --git a/server/middlewares/dnt.ts b/server/middlewares/dnt.ts index 607def855..dd88005dd 100644 --- a/server/middlewares/dnt.ts +++ b/server/middlewares/dnt.ts | |||
@@ -1,6 +1,3 @@ | |||
1 | import * as ipaddr from 'ipaddr.js' | ||
2 | import { format } from 'util' | ||
3 | |||
4 | const advertiseDoNotTrack = (_, res, next) => { | 1 | const advertiseDoNotTrack = (_, res, next) => { |
5 | res.setHeader('Tk', 'N') | 2 | res.setHeader('Tk', 'N') |
6 | return next() | 3 | return next() |
diff --git a/server/middlewares/oauth.ts b/server/middlewares/oauth.ts index 749f5cccd..9eef03bb4 100644 --- a/server/middlewares/oauth.ts +++ b/server/middlewares/oauth.ts | |||
@@ -51,6 +51,7 @@ function authenticateSocket (socket: Socket, next: (err?: any) => void) { | |||
51 | 51 | ||
52 | return next() | 52 | return next() |
53 | }) | 53 | }) |
54 | .catch(err => logger.error('Cannot get access token.', { err })) | ||
54 | } | 55 | } |
55 | 56 | ||
56 | function authenticatePromiseIfNeeded (req: express.Request, res: express.Response, authenticateInQuery = false) { | 57 | function authenticatePromiseIfNeeded (req: express.Request, res: express.Response, authenticateInQuery = false) { |
diff --git a/server/middlewares/sort.ts b/server/middlewares/sort.ts index 8c27e8237..fcbb2902c 100644 --- a/server/middlewares/sort.ts +++ b/server/middlewares/sort.ts | |||
@@ -1,20 +1,14 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { SortType } from '../models/utils' | 2 | import { SortType } from '../models/utils' |
3 | 3 | ||
4 | function setDefaultSort (req: express.Request, res: express.Response, next: express.NextFunction) { | 4 | const setDefaultSort = setDefaultSortFactory('-createdAt') |
5 | if (!req.query.sort) req.query.sort = '-createdAt' | ||
6 | |||
7 | return next() | ||
8 | } | ||
9 | 5 | ||
10 | function setDefaultSearchSort (req: express.Request, res: express.Response, next: express.NextFunction) { | 6 | const setDefaultVideoRedundanciesSort = setDefaultSortFactory('name') |
11 | if (!req.query.sort) req.query.sort = '-match' | ||
12 | 7 | ||
13 | return next() | 8 | const setDefaultSearchSort = setDefaultSortFactory('-match') |
14 | } | ||
15 | 9 | ||
16 | function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) { | 10 | function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) { |
17 | let newSort: SortType = { sortModel: undefined, sortValue: '' } | 11 | const newSort: SortType = { sortModel: undefined, sortValue: '' } |
18 | 12 | ||
19 | if (!req.query.sort) req.query.sort = '-createdAt' | 13 | if (!req.query.sort) req.query.sort = '-createdAt' |
20 | 14 | ||
@@ -39,5 +33,16 @@ function setBlacklistSort (req: express.Request, res: express.Response, next: ex | |||
39 | export { | 33 | export { |
40 | setDefaultSort, | 34 | setDefaultSort, |
41 | setDefaultSearchSort, | 35 | setDefaultSearchSort, |
36 | setDefaultVideoRedundanciesSort, | ||
42 | setBlacklistSort | 37 | setBlacklistSort |
43 | } | 38 | } |
39 | |||
40 | // --------------------------------------------------------------------------- | ||
41 | |||
42 | function setDefaultSortFactory (sort: string) { | ||
43 | return (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
44 | if (!req.query.sort) req.query.sort = sort | ||
45 | |||
46 | return next() | ||
47 | } | ||
48 | } | ||
diff --git a/server/middlewares/validators/avatar.ts b/server/middlewares/validators/avatar.ts index 8623d07e8..2acb97483 100644 --- a/server/middlewares/validators/avatar.ts +++ b/server/middlewares/validators/avatar.ts | |||
@@ -8,8 +8,8 @@ import { cleanUpReqFiles } from '../../helpers/express-utils' | |||
8 | 8 | ||
9 | const updateAvatarValidator = [ | 9 | const updateAvatarValidator = [ |
10 | body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( | 10 | body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( |
11 | 'This file is not supported or too large. Please, make sure it is of the following type : ' | 11 | 'This file is not supported or too large. Please, make sure it is of the following type : ' + |
12 | + CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ') | 12 | CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ') |
13 | ), | 13 | ), |
14 | 14 | ||
15 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 15 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts index 2d1f61947..ceab646c0 100644 --- a/server/middlewares/validators/config.ts +++ b/server/middlewares/validators/config.ts | |||
@@ -55,7 +55,7 @@ const customConfigUpdateValidator = [ | |||
55 | 55 | ||
56 | body('theme.default').custom(v => isThemeNameValid(v) && isThemeRegistered(v)).withMessage('Should have a valid theme'), | 56 | body('theme.default').custom(v => isThemeNameValid(v) && isThemeRegistered(v)).withMessage('Should have a valid theme'), |
57 | 57 | ||
58 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 58 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
59 | logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body }) | 59 | logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body }) |
60 | 60 | ||
61 | if (areValidationErrors(req, res)) return | 61 | if (areValidationErrors(req, res)) return |
diff --git a/server/middlewares/validators/feeds.ts b/server/middlewares/validators/feeds.ts index 29f6c87be..f34c2b174 100644 --- a/server/middlewares/validators/feeds.ts +++ b/server/middlewares/validators/feeds.ts | |||
@@ -22,13 +22,13 @@ function setFeedFormatContentType (req: express.Request, res: express.Response, | |||
22 | 22 | ||
23 | let acceptableContentTypes: string[] | 23 | let acceptableContentTypes: string[] |
24 | if (format === 'atom' || format === 'atom1') { | 24 | if (format === 'atom' || format === 'atom1') { |
25 | acceptableContentTypes = ['application/atom+xml', 'application/xml', 'text/xml'] | 25 | acceptableContentTypes = [ 'application/atom+xml', 'application/xml', 'text/xml' ] |
26 | } else if (format === 'json' || format === 'json1') { | 26 | } else if (format === 'json' || format === 'json1') { |
27 | acceptableContentTypes = ['application/json'] | 27 | acceptableContentTypes = [ 'application/json' ] |
28 | } else if (format === 'rss' || format === 'rss2') { | 28 | } else if (format === 'rss' || format === 'rss2') { |
29 | acceptableContentTypes = ['application/rss+xml', 'application/xml', 'text/xml'] | 29 | acceptableContentTypes = [ 'application/rss+xml', 'application/xml', 'text/xml' ] |
30 | } else { | 30 | } else { |
31 | acceptableContentTypes = ['application/xml', 'text/xml'] | 31 | acceptableContentTypes = [ 'application/xml', 'text/xml' ] |
32 | } | 32 | } |
33 | 33 | ||
34 | if (req.accepts(acceptableContentTypes)) { | 34 | if (req.accepts(acceptableContentTypes)) { |
diff --git a/server/middlewares/validators/redundancy.ts b/server/middlewares/validators/redundancy.ts index 8098e3a44..8cd3bc33d 100644 --- a/server/middlewares/validators/redundancy.ts +++ b/server/middlewares/validators/redundancy.ts | |||
@@ -1,12 +1,13 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { body, param } from 'express-validator' | 2 | import { body, param, query } from 'express-validator' |
3 | import { exists, isBooleanValid, isIdOrUUIDValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' | 3 | import { exists, isBooleanValid, isIdOrUUIDValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' |
4 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../helpers/logger' |
5 | import { areValidationErrors } from './utils' | 5 | import { areValidationErrors } from './utils' |
6 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' | 6 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' |
7 | import { isHostValid } from '../../helpers/custom-validators/servers' | 7 | import { isHostValid } from '../../helpers/custom-validators/servers' |
8 | import { ServerModel } from '../../models/server/server' | 8 | import { ServerModel } from '../../models/server/server' |
9 | import { doesVideoExist } from '../../helpers/middlewares' | 9 | import { doesVideoExist } from '../../helpers/middlewares' |
10 | import { isVideoRedundancyTarget } from '@server/helpers/custom-validators/video-redundancies' | ||
10 | 11 | ||
11 | const videoFileRedundancyGetValidator = [ | 12 | const videoFileRedundancyGetValidator = [ |
12 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), | 13 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), |
@@ -101,10 +102,77 @@ const updateServerRedundancyValidator = [ | |||
101 | } | 102 | } |
102 | ] | 103 | ] |
103 | 104 | ||
105 | const listVideoRedundanciesValidator = [ | ||
106 | query('target') | ||
107 | .custom(isVideoRedundancyTarget).withMessage('Should have a valid video redundancies target'), | ||
108 | |||
109 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
110 | logger.debug('Checking listVideoRedundanciesValidator parameters', { parameters: req.query }) | ||
111 | |||
112 | if (areValidationErrors(req, res)) return | ||
113 | |||
114 | return next() | ||
115 | } | ||
116 | ] | ||
117 | |||
118 | const addVideoRedundancyValidator = [ | ||
119 | body('videoId') | ||
120 | .custom(isIdValid) | ||
121 | .withMessage('Should have a valid video id'), | ||
122 | |||
123 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
124 | logger.debug('Checking addVideoRedundancyValidator parameters', { parameters: req.query }) | ||
125 | |||
126 | if (areValidationErrors(req, res)) return | ||
127 | |||
128 | if (!await doesVideoExist(req.body.videoId, res, 'only-video')) return | ||
129 | |||
130 | if (res.locals.onlyVideo.remote === false) { | ||
131 | return res.status(400) | ||
132 | .json({ error: 'Cannot create a redundancy on a local video' }) | ||
133 | .end() | ||
134 | } | ||
135 | |||
136 | const alreadyExists = await VideoRedundancyModel.isLocalByVideoUUIDExists(res.locals.onlyVideo.uuid) | ||
137 | if (alreadyExists) { | ||
138 | return res.status(409) | ||
139 | .json({ error: 'This video is already duplicated by your instance.' }) | ||
140 | } | ||
141 | |||
142 | return next() | ||
143 | } | ||
144 | ] | ||
145 | |||
146 | const removeVideoRedundancyValidator = [ | ||
147 | param('redundancyId') | ||
148 | .custom(isIdValid) | ||
149 | .withMessage('Should have a valid redundancy id'), | ||
150 | |||
151 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
152 | logger.debug('Checking removeVideoRedundancyValidator parameters', { parameters: req.query }) | ||
153 | |||
154 | if (areValidationErrors(req, res)) return | ||
155 | |||
156 | const redundancy = await VideoRedundancyModel.loadByIdWithVideo(parseInt(req.params.redundancyId, 10)) | ||
157 | if (!redundancy) { | ||
158 | return res.status(404) | ||
159 | .json({ error: 'Video redundancy not found' }) | ||
160 | .end() | ||
161 | } | ||
162 | |||
163 | res.locals.videoRedundancy = redundancy | ||
164 | |||
165 | return next() | ||
166 | } | ||
167 | ] | ||
168 | |||
104 | // --------------------------------------------------------------------------- | 169 | // --------------------------------------------------------------------------- |
105 | 170 | ||
106 | export { | 171 | export { |
107 | videoFileRedundancyGetValidator, | 172 | videoFileRedundancyGetValidator, |
108 | videoPlaylistRedundancyGetValidator, | 173 | videoPlaylistRedundancyGetValidator, |
109 | updateServerRedundancyValidator | 174 | updateServerRedundancyValidator, |
175 | listVideoRedundanciesValidator, | ||
176 | addVideoRedundancyValidator, | ||
177 | removeVideoRedundancyValidator | ||
110 | } | 178 | } |
diff --git a/server/middlewares/validators/sort.ts b/server/middlewares/validators/sort.ts index c75e701d6..b76dab722 100644 --- a/server/middlewares/validators/sort.ts +++ b/server/middlewares/validators/sort.ts | |||
@@ -23,6 +23,7 @@ const SORTABLE_USER_NOTIFICATIONS_COLUMNS = createSortableColumns(SORTABLE_COLUM | |||
23 | const SORTABLE_VIDEO_PLAYLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_PLAYLISTS) | 23 | const SORTABLE_VIDEO_PLAYLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_PLAYLISTS) |
24 | const SORTABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.PLUGINS) | 24 | const SORTABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.PLUGINS) |
25 | const SORTABLE_AVAILABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.AVAILABLE_PLUGINS) | 25 | const SORTABLE_AVAILABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.AVAILABLE_PLUGINS) |
26 | const SORTABLE_VIDEO_REDUNDANCIES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_REDUNDANCIES) | ||
26 | 27 | ||
27 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) | 28 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) |
28 | const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS) | 29 | const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS) |
@@ -45,6 +46,7 @@ const userNotificationsSortValidator = checkSort(SORTABLE_USER_NOTIFICATIONS_COL | |||
45 | const videoPlaylistsSortValidator = checkSort(SORTABLE_VIDEO_PLAYLISTS_COLUMNS) | 46 | const videoPlaylistsSortValidator = checkSort(SORTABLE_VIDEO_PLAYLISTS_COLUMNS) |
46 | const pluginsSortValidator = checkSort(SORTABLE_PLUGINS_COLUMNS) | 47 | const pluginsSortValidator = checkSort(SORTABLE_PLUGINS_COLUMNS) |
47 | const availablePluginsSortValidator = checkSort(SORTABLE_AVAILABLE_PLUGINS_COLUMNS) | 48 | const availablePluginsSortValidator = checkSort(SORTABLE_AVAILABLE_PLUGINS_COLUMNS) |
49 | const videoRedundanciesSortValidator = checkSort(SORTABLE_VIDEO_REDUNDANCIES_COLUMNS) | ||
48 | 50 | ||
49 | // --------------------------------------------------------------------------- | 51 | // --------------------------------------------------------------------------- |
50 | 52 | ||
@@ -69,5 +71,6 @@ export { | |||
69 | serversBlocklistSortValidator, | 71 | serversBlocklistSortValidator, |
70 | userNotificationsSortValidator, | 72 | userNotificationsSortValidator, |
71 | videoPlaylistsSortValidator, | 73 | videoPlaylistsSortValidator, |
74 | videoRedundanciesSortValidator, | ||
72 | pluginsSortValidator | 75 | pluginsSortValidator |
73 | } | 76 | } |
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index c78c67a8c..5d52b5804 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts | |||
@@ -36,7 +36,6 @@ import { doesVideoExist } from '../../helpers/middlewares' | |||
36 | import { UserRole } from '../../../shared/models/users' | 36 | import { UserRole } from '../../../shared/models/users' |
37 | import { MUserDefault } from '@server/typings/models' | 37 | import { MUserDefault } from '@server/typings/models' |
38 | import { Hooks } from '@server/lib/plugins/hooks' | 38 | import { Hooks } from '@server/lib/plugins/hooks' |
39 | import { isLocalVideoAccepted } from '@server/lib/moderation' | ||
40 | 39 | ||
41 | const usersAddValidator = [ | 40 | const usersAddValidator = [ |
42 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), | 41 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), |
@@ -149,7 +148,7 @@ const usersBlockingValidator = [ | |||
149 | ] | 148 | ] |
150 | 149 | ||
151 | const deleteMeValidator = [ | 150 | const deleteMeValidator = [ |
152 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 151 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
153 | const user = res.locals.oauth.token.User | 152 | const user = res.locals.oauth.token.User |
154 | if (user.username === 'root') { | 153 | if (user.username === 'root') { |
155 | return res.status(400) | 154 | return res.status(400) |
@@ -303,7 +302,7 @@ const ensureUserRegistrationAllowed = [ | |||
303 | ] | 302 | ] |
304 | 303 | ||
305 | const ensureUserRegistrationAllowedForIP = [ | 304 | const ensureUserRegistrationAllowedForIP = [ |
306 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 305 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
307 | const allowed = isSignupAllowedForCurrentIP(req.ip) | 306 | const allowed = isSignupAllowedForCurrentIP(req.ip) |
308 | 307 | ||
309 | if (allowed === false) { | 308 | if (allowed === false) { |
@@ -410,7 +409,7 @@ const userAutocompleteValidator = [ | |||
410 | ] | 409 | ] |
411 | 410 | ||
412 | const ensureAuthUserOwnsAccountValidator = [ | 411 | const ensureAuthUserOwnsAccountValidator = [ |
413 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 412 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
414 | const user = res.locals.oauth.token.User | 413 | const user = res.locals.oauth.token.User |
415 | 414 | ||
416 | if (res.locals.account.id !== user.Account.id) { | 415 | if (res.locals.account.id !== user.Account.id) { |
diff --git a/server/middlewares/validators/videos/video-captions.ts b/server/middlewares/validators/videos/video-captions.ts index 7b0cd6f66..872d9c2ab 100644 --- a/server/middlewares/validators/videos/video-captions.ts +++ b/server/middlewares/validators/videos/video-captions.ts | |||
@@ -13,10 +13,12 @@ const addVideoCaptionValidator = [ | |||
13 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), | 13 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), |
14 | param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'), | 14 | param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'), |
15 | body('captionfile') | 15 | body('captionfile') |
16 | .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile')).withMessage( | 16 | .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile')) |
17 | `This caption file is not supported or too large. Please, make sure it is under ${CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE} and one of the following mimetypes: ` | 17 | .withMessage( |
18 | + Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT).map(key => `${key} (${MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT[key]})`).join(', ') | 18 | 'This caption file is not supported or too large. ' + |
19 | ), | 19 | `Please, make sure it is under ${CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE} and one of the following mimetypes: ` + |
20 | Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT).map(key => `${key} (${MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT[key]})`).join(', ') | ||
21 | ), | ||
20 | 22 | ||
21 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 23 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
22 | logger.debug('Checking addVideoCaption parameters', { parameters: req.body }) | 24 | logger.debug('Checking addVideoCaption parameters', { parameters: req.body }) |
diff --git a/server/middlewares/validators/videos/video-comments.ts b/server/middlewares/validators/videos/video-comments.ts index 77c5f940d..da2fafb10 100644 --- a/server/middlewares/validators/videos/video-comments.ts +++ b/server/middlewares/validators/videos/video-comments.ts | |||
@@ -50,7 +50,7 @@ const addVideoCommentThreadValidator = [ | |||
50 | if (areValidationErrors(req, res)) return | 50 | if (areValidationErrors(req, res)) return |
51 | if (!await doesVideoExist(req.params.videoId, res)) return | 51 | if (!await doesVideoExist(req.params.videoId, res)) return |
52 | if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return | 52 | if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return |
53 | if (!await isVideoCommentAccepted(req, res, res.locals.videoAll,false)) return | 53 | if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, false)) return |
54 | 54 | ||
55 | return next() | 55 | return next() |
56 | } | 56 | } |
diff --git a/server/middlewares/validators/videos/video-imports.ts b/server/middlewares/validators/videos/video-imports.ts index 318dad100..5dc5db533 100644 --- a/server/middlewares/validators/videos/video-imports.ts +++ b/server/middlewares/validators/videos/video-imports.ts | |||
@@ -22,10 +22,11 @@ const videoImportAddValidator = getCommonVideoEditAttributes().concat([ | |||
22 | .optional() | 22 | .optional() |
23 | .custom(isVideoMagnetUriValid).withMessage('Should have a valid video magnet URI'), | 23 | .custom(isVideoMagnetUriValid).withMessage('Should have a valid video magnet URI'), |
24 | body('torrentfile') | 24 | body('torrentfile') |
25 | .custom((value, { req }) => isVideoImportTorrentFile(req.files)).withMessage( | 25 | .custom((value, { req }) => isVideoImportTorrentFile(req.files)) |
26 | 'This torrent file is not supported or too large. Please, make sure it is of the following type: ' | 26 | .withMessage( |
27 | + CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.EXTNAME.join(', ') | 27 | 'This torrent file is not supported or too large. Please, make sure it is of the following type: ' + |
28 | ), | 28 | CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.EXTNAME.join(', ') |
29 | ), | ||
29 | body('name') | 30 | body('name') |
30 | .optional() | 31 | .optional() |
31 | .custom(isVideoNameValid).withMessage('Should have a valid name'), | 32 | .custom(isVideoNameValid).withMessage('Should have a valid name'), |
diff --git a/server/middlewares/validators/videos/video-playlists.ts b/server/middlewares/validators/videos/video-playlists.ts index 1d67e8666..6b15c5464 100644 --- a/server/middlewares/validators/videos/video-playlists.ts +++ b/server/middlewares/validators/videos/video-playlists.ts | |||
@@ -384,10 +384,11 @@ export { | |||
384 | function getCommonPlaylistEditAttributes () { | 384 | function getCommonPlaylistEditAttributes () { |
385 | return [ | 385 | return [ |
386 | body('thumbnailfile') | 386 | body('thumbnailfile') |
387 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( | 387 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')) |
388 | 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' | 388 | .withMessage( |
389 | + CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ') | 389 | 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' + |
390 | ), | 390 | CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ') |
391 | ), | ||
391 | 392 | ||
392 | body('description') | 393 | body('description') |
393 | .optional() | 394 | .optional() |
diff --git a/server/middlewares/validators/videos/video-rates.ts b/server/middlewares/validators/videos/video-rates.ts index 4021cfecc..cbc144f69 100644 --- a/server/middlewares/validators/videos/video-rates.ts +++ b/server/middlewares/validators/videos/video-rates.ts | |||
@@ -24,7 +24,7 @@ const videoUpdateRateValidator = [ | |||
24 | } | 24 | } |
25 | ] | 25 | ] |
26 | 26 | ||
27 | const getAccountVideoRateValidator = function (rateType: VideoRateType) { | 27 | const getAccountVideoRateValidatorFactory = function (rateType: VideoRateType) { |
28 | return [ | 28 | return [ |
29 | param('name').custom(isAccountNameValid).withMessage('Should have a valid account name'), | 29 | param('name').custom(isAccountNameValid).withMessage('Should have a valid account name'), |
30 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), | 30 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), |
@@ -51,7 +51,7 @@ const getAccountVideoRateValidator = function (rateType: VideoRateType) { | |||
51 | const videoRatingValidator = [ | 51 | const videoRatingValidator = [ |
52 | query('rating').optional().custom(isRatingValid).withMessage('Value must be one of "like" or "dislike"'), | 52 | query('rating').optional().custom(isRatingValid).withMessage('Value must be one of "like" or "dislike"'), |
53 | 53 | ||
54 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 54 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
55 | logger.debug('Checking rating parameter', { parameters: req.params }) | 55 | logger.debug('Checking rating parameter', { parameters: req.params }) |
56 | 56 | ||
57 | if (areValidationErrors(req, res)) return | 57 | if (areValidationErrors(req, res)) return |
@@ -64,6 +64,6 @@ const videoRatingValidator = [ | |||
64 | 64 | ||
65 | export { | 65 | export { |
66 | videoUpdateRateValidator, | 66 | videoUpdateRateValidator, |
67 | getAccountVideoRateValidator, | 67 | getAccountVideoRateValidatorFactory, |
68 | videoRatingValidator | 68 | videoRatingValidator |
69 | } | 69 | } |
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index 6733d9dec..11dd02706 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts | |||
@@ -49,8 +49,8 @@ import { getVideoWithAttributes } from '../../../helpers/video' | |||
49 | const videosAddValidator = getCommonVideoEditAttributes().concat([ | 49 | const videosAddValidator = getCommonVideoEditAttributes().concat([ |
50 | body('videofile') | 50 | body('videofile') |
51 | .custom((value, { req }) => isVideoFile(req.files)).withMessage( | 51 | .custom((value, { req }) => isVideoFile(req.files)).withMessage( |
52 | 'This file is not supported or too large. Please, make sure it is of the following type: ' | 52 | 'This file is not supported or too large. Please, make sure it is of the following type: ' + |
53 | + CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') | 53 | CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') |
54 | ), | 54 | ), |
55 | body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), | 55 | body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), |
56 | body('channelId') | 56 | body('channelId') |
@@ -245,19 +245,15 @@ const videosTerminateChangeOwnershipValidator = [ | |||
245 | // Check if the user who did the request is able to change the ownership of the video | 245 | // Check if the user who did the request is able to change the ownership of the video |
246 | if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return | 246 | if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return |
247 | 247 | ||
248 | return next() | ||
249 | }, | ||
250 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
251 | const videoChangeOwnership = res.locals.videoChangeOwnership | 248 | const videoChangeOwnership = res.locals.videoChangeOwnership |
252 | 249 | ||
253 | if (videoChangeOwnership.status === VideoChangeOwnershipStatus.WAITING) { | 250 | if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) { |
254 | return next() | ||
255 | } else { | ||
256 | res.status(403) | 251 | res.status(403) |
257 | .json({ error: 'Ownership already accepted or refused' }) | 252 | .json({ error: 'Ownership already accepted or refused' }) |
258 | |||
259 | return | 253 | return |
260 | } | 254 | } |
255 | |||
256 | return next() | ||
261 | } | 257 | } |
262 | ] | 258 | ] |
263 | 259 | ||
@@ -284,14 +280,14 @@ function getCommonVideoEditAttributes () { | |||
284 | return [ | 280 | return [ |
285 | body('thumbnailfile') | 281 | body('thumbnailfile') |
286 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( | 282 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( |
287 | 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' | 283 | 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' + |
288 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') | 284 | CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') |
289 | ), | 285 | ), |
290 | body('previewfile') | 286 | body('previewfile') |
291 | .custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage( | 287 | .custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage( |
292 | 'This preview file is not supported or too large. Please, make sure it is of the following type: ' | 288 | 'This preview file is not supported or too large. Please, make sure it is of the following type: ' + |
293 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') | 289 | CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') |
294 | ), | 290 | ), |
295 | 291 | ||
296 | body('category') | 292 | body('category') |
297 | .optional() | 293 | .optional() |
diff --git a/server/middlewares/validators/webfinger.ts b/server/middlewares/validators/webfinger.ts index d50e6527f..5fe864f8b 100644 --- a/server/middlewares/validators/webfinger.ts +++ b/server/middlewares/validators/webfinger.ts | |||
@@ -18,15 +18,14 @@ const webfingerValidator = [ | |||
18 | const nameWithHost = getHostWithPort(req.query.resource.substr(5)) | 18 | const nameWithHost = getHostWithPort(req.query.resource.substr(5)) |
19 | const [ name ] = nameWithHost.split('@') | 19 | const [ name ] = nameWithHost.split('@') |
20 | 20 | ||
21 | // FIXME: we don't need the full actor | 21 | const actor = await ActorModel.loadLocalUrlByName(name) |
22 | const actor = await ActorModel.loadLocalByName(name) | ||
23 | if (!actor) { | 22 | if (!actor) { |
24 | return res.status(404) | 23 | return res.status(404) |
25 | .send({ error: 'Actor not found' }) | 24 | .send({ error: 'Actor not found' }) |
26 | .end() | 25 | .end() |
27 | } | 26 | } |
28 | 27 | ||
29 | res.locals.actorFull = actor | 28 | res.locals.actorUrl = actor |
30 | return next() | 29 | return next() |
31 | } | 30 | } |
32 | ] | 31 | ] |
diff --git a/server/models/account/account-blocklist.ts b/server/models/account/account-blocklist.ts index 6ebe32556..e2f66d733 100644 --- a/server/models/account/account-blocklist.ts +++ b/server/models/account/account-blocklist.ts | |||
@@ -80,7 +80,7 @@ export class AccountBlocklistModel extends Model<AccountBlocklistModel> { | |||
80 | attributes: [ 'accountId', 'id' ], | 80 | attributes: [ 'accountId', 'id' ], |
81 | where: { | 81 | where: { |
82 | accountId: { | 82 | accountId: { |
83 | [Op.in]: accountIds // FIXME: sequelize ANY seems broken | 83 | [Op.in]: accountIds |
84 | }, | 84 | }, |
85 | targetAccountId | 85 | targetAccountId |
86 | }, | 86 | }, |
diff --git a/server/models/account/account-video-rate.ts b/server/models/account/account-video-rate.ts index c593595b2..8aeb486d1 100644 --- a/server/models/account/account-video-rate.ts +++ b/server/models/account/account-video-rate.ts | |||
@@ -99,7 +99,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> { | |||
99 | static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, t?: Transaction): Bluebird<MAccountVideoRate> { | 99 | static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, t?: Transaction): Bluebird<MAccountVideoRate> { |
100 | const options: FindOptions = { | 100 | const options: FindOptions = { |
101 | where: { | 101 | where: { |
102 | [ Op.or]: [ | 102 | [Op.or]: [ |
103 | { | 103 | { |
104 | accountId, | 104 | accountId, |
105 | videoId | 105 | videoId |
@@ -116,10 +116,10 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> { | |||
116 | } | 116 | } |
117 | 117 | ||
118 | static listByAccountForApi (options: { | 118 | static listByAccountForApi (options: { |
119 | start: number, | 119 | start: number |
120 | count: number, | 120 | count: number |
121 | sort: string, | 121 | sort: string |
122 | type?: string, | 122 | type?: string |
123 | accountId: number | 123 | accountId: number |
124 | }) { | 124 | }) { |
125 | const query: FindOptions = { | 125 | const query: FindOptions = { |
@@ -135,7 +135,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> { | |||
135 | required: true, | 135 | required: true, |
136 | include: [ | 136 | include: [ |
137 | { | 137 | { |
138 | model: VideoChannelModel.scope({ method: [VideoChannelScopeNames.SUMMARY, { withAccount: true } as SummaryOptions ] }), | 138 | model: VideoChannelModel.scope({ method: [ VideoChannelScopeNames.SUMMARY, { withAccount: true } as SummaryOptions ] }), |
139 | required: true | 139 | required: true |
140 | } | 140 | } |
141 | ] | 141 | ] |
diff --git a/server/models/account/account.ts b/server/models/account/account.ts index 8a0ffeb63..0905a0fb2 100644 --- a/server/models/account/account.ts +++ b/server/models/account/account.ts | |||
@@ -53,7 +53,7 @@ export type SummaryOptions = { | |||
53 | ] | 53 | ] |
54 | })) | 54 | })) |
55 | @Scopes(() => ({ | 55 | @Scopes(() => ({ |
56 | [ ScopeNames.SUMMARY ]: (options: SummaryOptions = {}) => { | 56 | [ScopeNames.SUMMARY]: (options: SummaryOptions = {}) => { |
57 | const whereActor = options.whereActor || undefined | 57 | const whereActor = options.whereActor || undefined |
58 | 58 | ||
59 | const serverInclude: IncludeOptions = { | 59 | const serverInclude: IncludeOptions = { |
@@ -254,15 +254,15 @@ export class AccountModel extends Model<AccountModel> { | |||
254 | 254 | ||
255 | const query = { | 255 | const query = { |
256 | where: { | 256 | where: { |
257 | [ Op.or ]: [ | 257 | [Op.or]: [ |
258 | { | 258 | { |
259 | userId: { | 259 | userId: { |
260 | [ Op.ne ]: null | 260 | [Op.ne]: null |
261 | } | 261 | } |
262 | }, | 262 | }, |
263 | { | 263 | { |
264 | applicationId: { | 264 | applicationId: { |
265 | [ Op.ne ]: null | 265 | [Op.ne]: null |
266 | } | 266 | } |
267 | } | 267 | } |
268 | ] | 268 | ] |
diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts index a05f30175..5a725187a 100644 --- a/server/models/account/user-notification.ts +++ b/server/models/account/user-notification.ts | |||
@@ -363,7 +363,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
363 | where: { | 363 | where: { |
364 | userId, | 364 | userId, |
365 | id: { | 365 | id: { |
366 | [Op.in]: notificationIds // FIXME: sequelize ANY seems broken | 366 | [Op.in]: notificationIds |
367 | } | 367 | } |
368 | } | 368 | } |
369 | } | 369 | } |
@@ -379,7 +379,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
379 | 379 | ||
380 | toFormattedJSON (this: UserNotificationModelForApi): UserNotification { | 380 | toFormattedJSON (this: UserNotificationModelForApi): UserNotification { |
381 | const video = this.Video | 381 | const video = this.Video |
382 | ? Object.assign(this.formatVideo(this.Video),{ channel: this.formatActor(this.Video.VideoChannel) }) | 382 | ? Object.assign(this.formatVideo(this.Video), { channel: this.formatActor(this.Video.VideoChannel) }) |
383 | : undefined | 383 | : undefined |
384 | 384 | ||
385 | const videoImport = this.VideoImport ? { | 385 | const videoImport = this.VideoImport ? { |
diff --git a/server/models/account/user.ts b/server/models/account/user.ts index 4c2c5e278..fb4c15aef 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { FindOptions, literal, Op, QueryTypes, where, fn, col } from 'sequelize' | 1 | import { FindOptions, literal, Op, QueryTypes, where, fn, col, WhereOptions } from 'sequelize' |
2 | import { | 2 | import { |
3 | AfterDestroy, | 3 | AfterDestroy, |
4 | AfterUpdate, | 4 | AfterUpdate, |
@@ -101,7 +101,7 @@ enum ScopeNames { | |||
101 | required: true, | 101 | required: true, |
102 | where: { | 102 | where: { |
103 | type: { | 103 | type: { |
104 | [ Op.ne ]: VideoPlaylistType.REGULAR | 104 | [Op.ne]: VideoPlaylistType.REGULAR |
105 | } | 105 | } |
106 | } | 106 | } |
107 | } | 107 | } |
@@ -186,7 +186,10 @@ export class UserModel extends Model<UserModel> { | |||
186 | 186 | ||
187 | @AllowNull(false) | 187 | @AllowNull(false) |
188 | @Default(true) | 188 | @Default(true) |
189 | @Is('UserAutoPlayNextVideoPlaylist', value => throwIfNotValid(value, isUserAutoPlayNextVideoPlaylistValid, 'auto play next video for playlists boolean')) | 189 | @Is( |
190 | 'UserAutoPlayNextVideoPlaylist', | ||
191 | value => throwIfNotValid(value, isUserAutoPlayNextVideoPlaylistValid, 'auto play next video for playlists boolean') | ||
192 | ) | ||
190 | @Column | 193 | @Column |
191 | autoPlayNextVideoPlaylist: boolean | 194 | autoPlayNextVideoPlaylist: boolean |
192 | 195 | ||
@@ -308,7 +311,8 @@ export class UserModel extends Model<UserModel> { | |||
308 | } | 311 | } |
309 | 312 | ||
310 | static listForApi (start: number, count: number, sort: string, search?: string) { | 313 | static listForApi (start: number, count: number, sort: string, search?: string) { |
311 | let where = undefined | 314 | let where: WhereOptions |
315 | |||
312 | if (search) { | 316 | if (search) { |
313 | where = { | 317 | where = { |
314 | [Op.or]: [ | 318 | [Op.or]: [ |
@@ -319,7 +323,7 @@ export class UserModel extends Model<UserModel> { | |||
319 | }, | 323 | }, |
320 | { | 324 | { |
321 | username: { | 325 | username: { |
322 | [ Op.iLike ]: '%' + search + '%' | 326 | [Op.iLike]: '%' + search + '%' |
323 | } | 327 | } |
324 | } | 328 | } |
325 | ] | 329 | ] |
@@ -332,14 +336,14 @@ export class UserModel extends Model<UserModel> { | |||
332 | [ | 336 | [ |
333 | literal( | 337 | literal( |
334 | '(' + | 338 | '(' + |
335 | 'SELECT COALESCE(SUM("size"), 0) ' + | 339 | 'SELECT COALESCE(SUM("size"), 0) ' + |
336 | 'FROM (' + | 340 | 'FROM (' + |
337 | 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' + | 341 | 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' + |
338 | 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' + | 342 | 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' + |
339 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | 343 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + |
340 | 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' + | 344 | 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' + |
341 | 'WHERE "account"."userId" = "UserModel"."id" GROUP BY "video"."id"' + | 345 | 'WHERE "account"."userId" = "UserModel"."id" GROUP BY "video"."id"' + |
342 | ') t' + | 346 | ') t' + |
343 | ')' | 347 | ')' |
344 | ), | 348 | ), |
345 | 'videoQuotaUsed' | 349 | 'videoQuotaUsed' |
@@ -353,18 +357,18 @@ export class UserModel extends Model<UserModel> { | |||
353 | } | 357 | } |
354 | 358 | ||
355 | return UserModel.findAndCountAll(query) | 359 | return UserModel.findAndCountAll(query) |
356 | .then(({ rows, count }) => { | 360 | .then(({ rows, count }) => { |
357 | return { | 361 | return { |
358 | data: rows, | 362 | data: rows, |
359 | total: count | 363 | total: count |
360 | } | 364 | } |
361 | }) | 365 | }) |
362 | } | 366 | } |
363 | 367 | ||
364 | static listWithRight (right: UserRight): Bluebird<MUserDefault[]> { | 368 | static listWithRight (right: UserRight): Bluebird<MUserDefault[]> { |
365 | const roles = Object.keys(USER_ROLE_LABELS) | 369 | const roles = Object.keys(USER_ROLE_LABELS) |
366 | .map(k => parseInt(k, 10) as UserRole) | 370 | .map(k => parseInt(k, 10) as UserRole) |
367 | .filter(role => hasUserRight(role, right)) | 371 | .filter(role => hasUserRight(role, right)) |
368 | 372 | ||
369 | const query = { | 373 | const query = { |
370 | where: { | 374 | where: { |
@@ -390,7 +394,7 @@ export class UserModel extends Model<UserModel> { | |||
390 | required: true, | 394 | required: true, |
391 | include: [ | 395 | include: [ |
392 | { | 396 | { |
393 | attributes: [ ], | 397 | attributes: [], |
394 | model: ActorModel.unscoped(), | 398 | model: ActorModel.unscoped(), |
395 | required: true, | 399 | required: true, |
396 | where: { | 400 | where: { |
@@ -398,7 +402,7 @@ export class UserModel extends Model<UserModel> { | |||
398 | }, | 402 | }, |
399 | include: [ | 403 | include: [ |
400 | { | 404 | { |
401 | attributes: [ ], | 405 | attributes: [], |
402 | as: 'ActorFollowings', | 406 | as: 'ActorFollowings', |
403 | model: ActorFollowModel.unscoped(), | 407 | model: ActorFollowModel.unscoped(), |
404 | required: true, | 408 | required: true, |
@@ -433,7 +437,7 @@ export class UserModel extends Model<UserModel> { | |||
433 | static loadByUsername (username: string): Bluebird<MUserDefault> { | 437 | static loadByUsername (username: string): Bluebird<MUserDefault> { |
434 | const query = { | 438 | const query = { |
435 | where: { | 439 | where: { |
436 | username: { [ Op.iLike ]: username } | 440 | username: { [Op.iLike]: username } |
437 | } | 441 | } |
438 | } | 442 | } |
439 | 443 | ||
@@ -443,7 +447,7 @@ export class UserModel extends Model<UserModel> { | |||
443 | static loadForMeAPI (username: string): Bluebird<MUserNotifSettingChannelDefault> { | 447 | static loadForMeAPI (username: string): Bluebird<MUserNotifSettingChannelDefault> { |
444 | const query = { | 448 | const query = { |
445 | where: { | 449 | where: { |
446 | username: { [ Op.iLike ]: username } | 450 | username: { [Op.iLike]: username } |
447 | } | 451 | } |
448 | } | 452 | } |
449 | 453 | ||
@@ -465,7 +469,7 @@ export class UserModel extends Model<UserModel> { | |||
465 | 469 | ||
466 | const query = { | 470 | const query = { |
467 | where: { | 471 | where: { |
468 | [ Op.or ]: [ | 472 | [Op.or]: [ |
469 | where(fn('lower', col('username')), fn('lower', username)), | 473 | where(fn('lower', col('username')), fn('lower', username)), |
470 | 474 | ||
471 | { email } | 475 | { email } |
@@ -592,7 +596,7 @@ export class UserModel extends Model<UserModel> { | |||
592 | const query = { | 596 | const query = { |
593 | where: { | 597 | where: { |
594 | username: { | 598 | username: { |
595 | [ Op.like ]: `%${search}%` | 599 | [Op.like]: `%${search}%` |
596 | } | 600 | } |
597 | }, | 601 | }, |
598 | limit: 10 | 602 | limit: 10 |
@@ -652,7 +656,7 @@ export class UserModel extends Model<UserModel> { | |||
652 | videoLanguages: this.videoLanguages, | 656 | videoLanguages: this.videoLanguages, |
653 | 657 | ||
654 | role: this.role, | 658 | role: this.role, |
655 | roleLabel: USER_ROLE_LABELS[ this.role ], | 659 | roleLabel: USER_ROLE_LABELS[this.role], |
656 | 660 | ||
657 | videoQuota: this.videoQuota, | 661 | videoQuota: this.videoQuota, |
658 | videoQuotaDaily: this.videoQuotaDaily, | 662 | videoQuotaDaily: this.videoQuotaDaily, |
@@ -686,13 +690,13 @@ export class UserModel extends Model<UserModel> { | |||
686 | 690 | ||
687 | if (Array.isArray(this.Account.VideoChannels) === true) { | 691 | if (Array.isArray(this.Account.VideoChannels) === true) { |
688 | json.videoChannels = this.Account.VideoChannels | 692 | json.videoChannels = this.Account.VideoChannels |
689 | .map(c => c.toFormattedJSON()) | 693 | .map(c => c.toFormattedJSON()) |
690 | .sort((v1, v2) => { | 694 | .sort((v1, v2) => { |
691 | if (v1.createdAt < v2.createdAt) return -1 | 695 | if (v1.createdAt < v2.createdAt) return -1 |
692 | if (v1.createdAt === v2.createdAt) return 0 | 696 | if (v1.createdAt === v2.createdAt) return 0 |
693 | 697 | ||
694 | return 1 | 698 | return 1 |
695 | }) | 699 | }) |
696 | } | 700 | } |
697 | 701 | ||
698 | return json | 702 | return json |
@@ -702,7 +706,7 @@ export class UserModel extends Model<UserModel> { | |||
702 | const formatted = this.toFormattedJSON() | 706 | const formatted = this.toFormattedJSON() |
703 | 707 | ||
704 | const specialPlaylists = this.Account.VideoPlaylists | 708 | const specialPlaylists = this.Account.VideoPlaylists |
705 | .map(p => ({ id: p.id, name: p.name, type: p.type })) | 709 | .map(p => ({ id: p.id, name: p.name, type: p.type })) |
706 | 710 | ||
707 | return Object.assign(formatted, { specialPlaylists }) | 711 | return Object.assign(formatted, { specialPlaylists }) |
708 | } | 712 | } |
@@ -729,12 +733,12 @@ export class UserModel extends Model<UserModel> { | |||
729 | 733 | ||
730 | return 'SELECT SUM("size") AS "total" ' + | 734 | return 'SELECT SUM("size") AS "total" ' + |
731 | 'FROM (' + | 735 | 'FROM (' + |
732 | 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' + | 736 | 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' + |
733 | 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' + | 737 | 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' + |
734 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | 738 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + |
735 | 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' + | 739 | 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' + |
736 | 'WHERE "account"."userId" = $userId ' + andWhere + | 740 | 'WHERE "account"."userId" = $userId ' + andWhere + |
737 | 'GROUP BY "video"."id"' + | 741 | 'GROUP BY "video"."id"' + |
738 | ') t' | 742 | ') t' |
739 | } | 743 | } |
740 | 744 | ||
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts index f21d2b8a2..27643704e 100644 --- a/server/models/activitypub/actor-follow.ts +++ b/server/models/activitypub/actor-follow.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { values, difference } from 'lodash' | 2 | import { difference, values } from 'lodash' |
3 | import { | 3 | import { |
4 | AfterCreate, | 4 | AfterCreate, |
5 | AfterDestroy, | 5 | AfterDestroy, |
@@ -23,7 +23,7 @@ import { logger } from '../../helpers/logger' | |||
23 | import { getServerActor } from '../../helpers/utils' | 23 | import { getServerActor } from '../../helpers/utils' |
24 | import { ACTOR_FOLLOW_SCORE, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants' | 24 | import { ACTOR_FOLLOW_SCORE, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants' |
25 | import { ServerModel } from '../server/server' | 25 | import { ServerModel } from '../server/server' |
26 | import { createSafeIn, getSort, getFollowsSort } from '../utils' | 26 | import { createSafeIn, getFollowsSort, getSort } from '../utils' |
27 | import { ActorModel, unusedActorAttributesForAPI } from './actor' | 27 | import { ActorModel, unusedActorAttributesForAPI } from './actor' |
28 | import { VideoChannelModel } from '../video/video-channel' | 28 | import { VideoChannelModel } from '../video/video-channel' |
29 | import { AccountModel } from '../account/account' | 29 | import { AccountModel } from '../account/account' |
@@ -36,7 +36,6 @@ import { | |||
36 | MActorFollowSubscriptions | 36 | MActorFollowSubscriptions |
37 | } from '@server/typings/models' | 37 | } from '@server/typings/models' |
38 | import { ActivityPubActorType } from '@shared/models' | 38 | import { ActivityPubActorType } from '@shared/models' |
39 | import { afterCommitIfTransaction } from '@server/helpers/database-utils' | ||
40 | 39 | ||
41 | @Table({ | 40 | @Table({ |
42 | tableName: 'actorFollow', | 41 | tableName: 'actorFollow', |
@@ -226,7 +225,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
226 | 225 | ||
227 | return ActorFollowModel.findOne(query) | 226 | return ActorFollowModel.findOne(query) |
228 | .then(result => { | 227 | .then(result => { |
229 | if (result && result.ActorFollowing.VideoChannel) { | 228 | if (result?.ActorFollowing.VideoChannel) { |
230 | result.ActorFollowing.VideoChannel.Actor = result.ActorFollowing | 229 | result.ActorFollowing.VideoChannel.Actor = result.ActorFollowing |
231 | } | 230 | } |
232 | 231 | ||
@@ -239,24 +238,24 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
239 | .map(t => { | 238 | .map(t => { |
240 | if (t.host) { | 239 | if (t.host) { |
241 | return { | 240 | return { |
242 | [ Op.and ]: [ | 241 | [Op.and]: [ |
243 | { | 242 | { |
244 | '$preferredUsername$': t.name | 243 | $preferredUsername$: t.name |
245 | }, | 244 | }, |
246 | { | 245 | { |
247 | '$host$': t.host | 246 | $host$: t.host |
248 | } | 247 | } |
249 | ] | 248 | ] |
250 | } | 249 | } |
251 | } | 250 | } |
252 | 251 | ||
253 | return { | 252 | return { |
254 | [ Op.and ]: [ | 253 | [Op.and]: [ |
255 | { | 254 | { |
256 | '$preferredUsername$': t.name | 255 | $preferredUsername$: t.name |
257 | }, | 256 | }, |
258 | { | 257 | { |
259 | '$serverId$': null | 258 | $serverId$: null |
260 | } | 259 | } |
261 | ] | 260 | ] |
262 | } | 261 | } |
@@ -265,9 +264,9 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
265 | const query = { | 264 | const query = { |
266 | attributes: [], | 265 | attributes: [], |
267 | where: { | 266 | where: { |
268 | [ Op.and ]: [ | 267 | [Op.and]: [ |
269 | { | 268 | { |
270 | [ Op.or ]: whereTab | 269 | [Op.or]: whereTab |
271 | }, | 270 | }, |
272 | { | 271 | { |
273 | actorId | 272 | actorId |
@@ -295,12 +294,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
295 | } | 294 | } |
296 | 295 | ||
297 | static listFollowingForApi (options: { | 296 | static listFollowingForApi (options: { |
298 | id: number, | 297 | id: number |
299 | start: number, | 298 | start: number |
300 | count: number, | 299 | count: number |
301 | sort: string, | 300 | sort: string |
302 | state?: FollowState, | 301 | state?: FollowState |
303 | actorType?: ActivityPubActorType, | 302 | actorType?: ActivityPubActorType |
304 | search?: string | 303 | search?: string |
305 | }) { | 304 | }) { |
306 | const { id, start, count, sort, search, state, actorType } = options | 305 | const { id, start, count, sort, search, state, actorType } = options |
@@ -312,7 +311,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
312 | if (search) { | 311 | if (search) { |
313 | Object.assign(followingServerWhere, { | 312 | Object.assign(followingServerWhere, { |
314 | host: { | 313 | host: { |
315 | [ Op.iLike ]: '%' + search + '%' | 314 | [Op.iLike]: '%' + search + '%' |
316 | } | 315 | } |
317 | }) | 316 | }) |
318 | } | 317 | } |
@@ -362,12 +361,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
362 | } | 361 | } |
363 | 362 | ||
364 | static listFollowersForApi (options: { | 363 | static listFollowersForApi (options: { |
365 | actorId: number, | 364 | actorId: number |
366 | start: number, | 365 | start: number |
367 | count: number, | 366 | count: number |
368 | sort: string, | 367 | sort: string |
369 | state?: FollowState, | 368 | state?: FollowState |
370 | actorType?: ActivityPubActorType, | 369 | actorType?: ActivityPubActorType |
371 | search?: string | 370 | search?: string |
372 | }) { | 371 | }) { |
373 | const { actorId, start, count, sort, search, state, actorType } = options | 372 | const { actorId, start, count, sort, search, state, actorType } = options |
@@ -379,7 +378,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
379 | if (search) { | 378 | if (search) { |
380 | Object.assign(followerServerWhere, { | 379 | Object.assign(followerServerWhere, { |
381 | host: { | 380 | host: { |
382 | [ Op.iLike ]: '%' + search + '%' | 381 | [Op.iLike]: '%' + search + '%' |
383 | } | 382 | } |
384 | }) | 383 | }) |
385 | } | 384 | } |
@@ -631,7 +630,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
631 | 630 | ||
632 | const tasks: Bluebird<any>[] = [] | 631 | const tasks: Bluebird<any>[] = [] |
633 | 632 | ||
634 | for (let selection of selections) { | 633 | for (const selection of selections) { |
635 | let query = 'SELECT ' + selection + ' FROM "actor" ' + | 634 | let query = 'SELECT ' + selection + ' FROM "actor" ' + |
636 | 'INNER JOIN "actorFollow" ON "actorFollow"."' + firstJoin + '" = "actor"."id" ' + | 635 | 'INNER JOIN "actorFollow" ON "actorFollow"."' + firstJoin + '" = "actor"."id" ' + |
637 | 'INNER JOIN "actor" AS "Follows" ON "actorFollow"."' + secondJoin + '" = "Follows"."id" ' + | 636 | 'INNER JOIN "actor" AS "Follows" ON "actorFollow"."' + secondJoin + '" = "Follows"."id" ' + |
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts index 007647ced..00e8dc954 100644 --- a/server/models/activitypub/actor.ts +++ b/server/models/activitypub/actor.ts | |||
@@ -16,7 +16,7 @@ import { | |||
16 | Table, | 16 | Table, |
17 | UpdatedAt | 17 | UpdatedAt |
18 | } from 'sequelize-typescript' | 18 | } from 'sequelize-typescript' |
19 | import { ActivityPubActorType } from '../../../shared/models/activitypub' | 19 | import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub' |
20 | import { Avatar } from '../../../shared/models/avatars/avatar.model' | 20 | import { Avatar } from '../../../shared/models/avatars/avatar.model' |
21 | import { activityPubContextify } from '../../helpers/activitypub' | 21 | import { activityPubContextify } from '../../helpers/activitypub' |
22 | import { | 22 | import { |
@@ -43,7 +43,7 @@ import { | |||
43 | MActorFull, | 43 | MActorFull, |
44 | MActorHost, | 44 | MActorHost, |
45 | MActorServer, | 45 | MActorServer, |
46 | MActorSummaryFormattable, | 46 | MActorSummaryFormattable, MActorUrl, |
47 | MActorWithInboxes | 47 | MActorWithInboxes |
48 | } from '../../typings/models' | 48 | } from '../../typings/models' |
49 | import * as Bluebird from 'bluebird' | 49 | import * as Bluebird from 'bluebird' |
@@ -276,7 +276,8 @@ export class ActorModel extends Model<ActorModel> { | |||
276 | }) | 276 | }) |
277 | VideoChannel: VideoChannelModel | 277 | VideoChannel: VideoChannelModel |
278 | 278 | ||
279 | private static cache: { [ id: string ]: any } = {} | 279 | private static localNameCache: { [ id: string ]: any } = {} |
280 | private static localUrlCache: { [ id: string ]: any } = {} | ||
280 | 281 | ||
281 | static load (id: number): Bluebird<MActor> { | 282 | static load (id: number): Bluebird<MActor> { |
282 | return ActorModel.unscoped().findByPk(id) | 283 | return ActorModel.unscoped().findByPk(id) |
@@ -334,7 +335,7 @@ export class ActorModel extends Model<ActorModel> { | |||
334 | const query = { | 335 | const query = { |
335 | where: { | 336 | where: { |
336 | followersUrl: { | 337 | followersUrl: { |
337 | [ Op.in ]: followersUrls | 338 | [Op.in]: followersUrls |
338 | } | 339 | } |
339 | }, | 340 | }, |
340 | transaction | 341 | transaction |
@@ -345,8 +346,8 @@ export class ActorModel extends Model<ActorModel> { | |||
345 | 346 | ||
346 | static loadLocalByName (preferredUsername: string, transaction?: Transaction): Bluebird<MActorFull> { | 347 | static loadLocalByName (preferredUsername: string, transaction?: Transaction): Bluebird<MActorFull> { |
347 | // The server actor never change, so we can easily cache it | 348 | // The server actor never change, so we can easily cache it |
348 | if (preferredUsername === SERVER_ACTOR_NAME && ActorModel.cache[preferredUsername]) { | 349 | if (preferredUsername === SERVER_ACTOR_NAME && ActorModel.localNameCache[preferredUsername]) { |
349 | return Bluebird.resolve(ActorModel.cache[preferredUsername]) | 350 | return Bluebird.resolve(ActorModel.localNameCache[preferredUsername]) |
350 | } | 351 | } |
351 | 352 | ||
352 | const query = { | 353 | const query = { |
@@ -361,7 +362,33 @@ export class ActorModel extends Model<ActorModel> { | |||
361 | .findOne(query) | 362 | .findOne(query) |
362 | .then(actor => { | 363 | .then(actor => { |
363 | if (preferredUsername === SERVER_ACTOR_NAME) { | 364 | if (preferredUsername === SERVER_ACTOR_NAME) { |
364 | ActorModel.cache[ preferredUsername ] = actor | 365 | ActorModel.localNameCache[preferredUsername] = actor |
366 | } | ||
367 | |||
368 | return actor | ||
369 | }) | ||
370 | } | ||
371 | |||
372 | static loadLocalUrlByName (preferredUsername: string, transaction?: Transaction): Bluebird<MActorUrl> { | ||
373 | // The server actor never change, so we can easily cache it | ||
374 | if (preferredUsername === SERVER_ACTOR_NAME && ActorModel.localUrlCache[preferredUsername]) { | ||
375 | return Bluebird.resolve(ActorModel.localUrlCache[preferredUsername]) | ||
376 | } | ||
377 | |||
378 | const query = { | ||
379 | attributes: [ 'url' ], | ||
380 | where: { | ||
381 | preferredUsername, | ||
382 | serverId: null | ||
383 | }, | ||
384 | transaction | ||
385 | } | ||
386 | |||
387 | return ActorModel.unscoped() | ||
388 | .findOne(query) | ||
389 | .then(actor => { | ||
390 | if (preferredUsername === SERVER_ACTOR_NAME) { | ||
391 | ActorModel.localUrlCache[preferredUsername] = actor | ||
365 | } | 392 | } |
366 | 393 | ||
367 | return actor | 394 | return actor |
@@ -473,9 +500,11 @@ export class ActorModel extends Model<ActorModel> { | |||
473 | } | 500 | } |
474 | 501 | ||
475 | toActivityPubObject (this: MActorAP, name: string) { | 502 | toActivityPubObject (this: MActorAP, name: string) { |
476 | let icon = undefined | 503 | let icon: ActivityIconObject |
504 | |||
477 | if (this.avatarId) { | 505 | if (this.avatarId) { |
478 | const extension = extname(this.Avatar.filename) | 506 | const extension = extname(this.Avatar.filename) |
507 | |||
479 | icon = { | 508 | icon = { |
480 | type: 'Image', | 509 | type: 'Image', |
481 | mediaType: extension === '.png' ? 'image/png' : 'image/jpeg', | 510 | mediaType: extension === '.png' ? 'image/png' : 'image/jpeg', |
diff --git a/server/models/oauth/oauth-token.ts b/server/models/oauth/oauth-token.ts index b680be237..d2101ce86 100644 --- a/server/models/oauth/oauth-token.ts +++ b/server/models/oauth/oauth-token.ts | |||
@@ -23,10 +23,10 @@ import { MOAuthTokenUser } from '@server/typings/models/oauth/oauth-token' | |||
23 | 23 | ||
24 | export type OAuthTokenInfo = { | 24 | export type OAuthTokenInfo = { |
25 | refreshToken: string | 25 | refreshToken: string |
26 | refreshTokenExpiresAt: Date, | 26 | refreshTokenExpiresAt: Date |
27 | client: { | 27 | client: { |
28 | id: number | 28 | id: number |
29 | }, | 29 | } |
30 | user: { | 30 | user: { |
31 | id: number | 31 | id: number |
32 | } | 32 | } |
diff --git a/server/models/redundancy/video-redundancy.ts b/server/models/redundancy/video-redundancy.ts index 8c9a7eabf..1b63d3818 100644 --- a/server/models/redundancy/video-redundancy.ts +++ b/server/models/redundancy/video-redundancy.ts | |||
@@ -13,13 +13,13 @@ import { | |||
13 | UpdatedAt | 13 | UpdatedAt |
14 | } from 'sequelize-typescript' | 14 | } from 'sequelize-typescript' |
15 | import { ActorModel } from '../activitypub/actor' | 15 | import { ActorModel } from '../activitypub/actor' |
16 | import { getVideoSort, parseAggregateResult, throwIfNotValid } from '../utils' | 16 | import { getSort, getVideoSort, parseAggregateResult, throwIfNotValid } from '../utils' |
17 | import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 17 | import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
18 | import { CONSTRAINTS_FIELDS, MIMETYPES } from '../../initializers/constants' | 18 | import { CONSTRAINTS_FIELDS, MIMETYPES } from '../../initializers/constants' |
19 | import { VideoFileModel } from '../video/video-file' | 19 | import { VideoFileModel } from '../video/video-file' |
20 | import { getServerActor } from '../../helpers/utils' | 20 | import { getServerActor } from '../../helpers/utils' |
21 | import { VideoModel } from '../video/video' | 21 | import { VideoModel } from '../video/video' |
22 | import { VideoRedundancyStrategy } from '../../../shared/models/redundancy' | 22 | import { VideoRedundancyStrategy, VideoRedundancyStrategyWithManual } from '../../../shared/models/redundancy' |
23 | import { logger } from '../../helpers/logger' | 23 | import { logger } from '../../helpers/logger' |
24 | import { CacheFileObject, VideoPrivacy } from '../../../shared' | 24 | import { CacheFileObject, VideoPrivacy } from '../../../shared' |
25 | import { VideoChannelModel } from '../video/video-channel' | 25 | import { VideoChannelModel } from '../video/video-channel' |
@@ -27,17 +27,23 @@ import { ServerModel } from '../server/server' | |||
27 | import { sample } from 'lodash' | 27 | import { sample } from 'lodash' |
28 | import { isTestInstance } from '../../helpers/core-utils' | 28 | import { isTestInstance } from '../../helpers/core-utils' |
29 | import * as Bluebird from 'bluebird' | 29 | import * as Bluebird from 'bluebird' |
30 | import { col, FindOptions, fn, literal, Op, Transaction } from 'sequelize' | 30 | import { col, FindOptions, fn, literal, Op, Transaction, WhereOptions } from 'sequelize' |
31 | import { VideoStreamingPlaylistModel } from '../video/video-streaming-playlist' | 31 | import { VideoStreamingPlaylistModel } from '../video/video-streaming-playlist' |
32 | import { CONFIG } from '../../initializers/config' | 32 | import { CONFIG } from '../../initializers/config' |
33 | import { MVideoRedundancy, MVideoRedundancyAP, MVideoRedundancyVideo } from '@server/typings/models' | 33 | import { MVideoForRedundancyAPI, MVideoRedundancy, MVideoRedundancyAP, MVideoRedundancyVideo } from '@server/typings/models' |
34 | import { VideoRedundanciesTarget } from '@shared/models/redundancy/video-redundancies-filters.model' | ||
35 | import { | ||
36 | FileRedundancyInformation, | ||
37 | StreamingPlaylistRedundancyInformation, | ||
38 | VideoRedundancy | ||
39 | } from '@shared/models/redundancy/video-redundancy.model' | ||
34 | 40 | ||
35 | export enum ScopeNames { | 41 | export enum ScopeNames { |
36 | WITH_VIDEO = 'WITH_VIDEO' | 42 | WITH_VIDEO = 'WITH_VIDEO' |
37 | } | 43 | } |
38 | 44 | ||
39 | @Scopes(() => ({ | 45 | @Scopes(() => ({ |
40 | [ ScopeNames.WITH_VIDEO ]: { | 46 | [ScopeNames.WITH_VIDEO]: { |
41 | include: [ | 47 | include: [ |
42 | { | 48 | { |
43 | model: VideoFileModel, | 49 | model: VideoFileModel, |
@@ -86,7 +92,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
86 | @UpdatedAt | 92 | @UpdatedAt |
87 | updatedAt: Date | 93 | updatedAt: Date |
88 | 94 | ||
89 | @AllowNull(false) | 95 | @AllowNull(true) |
90 | @Column | 96 | @Column |
91 | expiresOn: Date | 97 | expiresOn: Date |
92 | 98 | ||
@@ -161,7 +167,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
161 | logger.info('Removing duplicated video streaming playlist %s.', videoUUID) | 167 | logger.info('Removing duplicated video streaming playlist %s.', videoUUID) |
162 | 168 | ||
163 | videoStreamingPlaylist.Video.removeStreamingPlaylistFiles(videoStreamingPlaylist, true) | 169 | videoStreamingPlaylist.Video.removeStreamingPlaylistFiles(videoStreamingPlaylist, true) |
164 | .catch(err => logger.error('Cannot delete video streaming playlist files of %s.', videoUUID, { err })) | 170 | .catch(err => logger.error('Cannot delete video streaming playlist files of %s.', videoUUID, { err })) |
165 | } | 171 | } |
166 | 172 | ||
167 | return undefined | 173 | return undefined |
@@ -193,6 +199,15 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
193 | return VideoRedundancyModel.scope(ScopeNames.WITH_VIDEO).findOne(query) | 199 | return VideoRedundancyModel.scope(ScopeNames.WITH_VIDEO).findOne(query) |
194 | } | 200 | } |
195 | 201 | ||
202 | static loadByIdWithVideo (id: number, transaction?: Transaction): Bluebird<MVideoRedundancyVideo> { | ||
203 | const query = { | ||
204 | where: { id }, | ||
205 | transaction | ||
206 | } | ||
207 | |||
208 | return VideoRedundancyModel.scope(ScopeNames.WITH_VIDEO).findOne(query) | ||
209 | } | ||
210 | |||
196 | static loadByUrl (url: string, transaction?: Transaction): Bluebird<MVideoRedundancy> { | 211 | static loadByUrl (url: string, transaction?: Transaction): Bluebird<MVideoRedundancy> { |
197 | const query = { | 212 | const query = { |
198 | where: { | 213 | where: { |
@@ -215,12 +230,12 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
215 | }, | 230 | }, |
216 | include: [ | 231 | include: [ |
217 | { | 232 | { |
218 | attributes: [ ], | 233 | attributes: [], |
219 | model: VideoFileModel, | 234 | model: VideoFileModel, |
220 | required: true, | 235 | required: true, |
221 | include: [ | 236 | include: [ |
222 | { | 237 | { |
223 | attributes: [ ], | 238 | attributes: [], |
224 | model: VideoModel, | 239 | model: VideoModel, |
225 | required: true, | 240 | required: true, |
226 | where: { | 241 | where: { |
@@ -233,7 +248,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
233 | } | 248 | } |
234 | 249 | ||
235 | return VideoRedundancyModel.findOne(query) | 250 | return VideoRedundancyModel.findOne(query) |
236 | .then(r => !!r) | 251 | .then(r => !!r) |
237 | } | 252 | } |
238 | 253 | ||
239 | static async getVideoSample (p: Bluebird<VideoModel[]>) { | 254 | static async getVideoSample (p: Bluebird<VideoModel[]>) { |
@@ -295,7 +310,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
295 | where: { | 310 | where: { |
296 | privacy: VideoPrivacy.PUBLIC, | 311 | privacy: VideoPrivacy.PUBLIC, |
297 | views: { | 312 | views: { |
298 | [ Op.gte ]: minViews | 313 | [Op.gte]: minViews |
299 | } | 314 | } |
300 | }, | 315 | }, |
301 | include: [ | 316 | include: [ |
@@ -318,7 +333,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
318 | actorId: actor.id, | 333 | actorId: actor.id, |
319 | strategy, | 334 | strategy, |
320 | createdAt: { | 335 | createdAt: { |
321 | [ Op.lt ]: expiredDate | 336 | [Op.lt]: expiredDate |
322 | } | 337 | } |
323 | } | 338 | } |
324 | } | 339 | } |
@@ -377,7 +392,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
377 | where: { | 392 | where: { |
378 | actorId: actor.id, | 393 | actorId: actor.id, |
379 | expiresOn: { | 394 | expiresOn: { |
380 | [ Op.lt ]: new Date() | 395 | [Op.lt]: new Date() |
381 | } | 396 | } |
382 | } | 397 | } |
383 | } | 398 | } |
@@ -394,7 +409,8 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
394 | [Op.ne]: actor.id | 409 | [Op.ne]: actor.id |
395 | }, | 410 | }, |
396 | expiresOn: { | 411 | expiresOn: { |
397 | [ Op.lt ]: new Date() | 412 | [Op.lt]: new Date(), |
413 | [Op.ne]: null | ||
398 | } | 414 | } |
399 | } | 415 | } |
400 | } | 416 | } |
@@ -447,7 +463,112 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
447 | return VideoRedundancyModel.findAll(query) | 463 | return VideoRedundancyModel.findAll(query) |
448 | } | 464 | } |
449 | 465 | ||
450 | static async getStats (strategy: VideoRedundancyStrategy) { | 466 | static listForApi (options: { |
467 | start: number | ||
468 | count: number | ||
469 | sort: string | ||
470 | target: VideoRedundanciesTarget | ||
471 | strategy?: string | ||
472 | }) { | ||
473 | const { start, count, sort, target, strategy } = options | ||
474 | const redundancyWhere: WhereOptions = {} | ||
475 | const videosWhere: WhereOptions = {} | ||
476 | let redundancySqlSuffix = '' | ||
477 | |||
478 | if (target === 'my-videos') { | ||
479 | Object.assign(videosWhere, { remote: false }) | ||
480 | } else if (target === 'remote-videos') { | ||
481 | Object.assign(videosWhere, { remote: true }) | ||
482 | Object.assign(redundancyWhere, { strategy: { [Op.ne]: null } }) | ||
483 | redundancySqlSuffix = ' AND "videoRedundancy"."strategy" IS NOT NULL' | ||
484 | } | ||
485 | |||
486 | if (strategy) { | ||
487 | Object.assign(redundancyWhere, { strategy: strategy }) | ||
488 | } | ||
489 | |||
490 | const videoFilterWhere = { | ||
491 | [Op.and]: [ | ||
492 | { | ||
493 | [Op.or]: [ | ||
494 | { | ||
495 | id: { | ||
496 | [Op.in]: literal( | ||
497 | '(' + | ||
498 | 'SELECT "videoId" FROM "videoFile" ' + | ||
499 | 'INNER JOIN "videoRedundancy" ON "videoRedundancy"."videoFileId" = "videoFile".id' + | ||
500 | redundancySqlSuffix + | ||
501 | ')' | ||
502 | ) | ||
503 | } | ||
504 | }, | ||
505 | { | ||
506 | id: { | ||
507 | [Op.in]: literal( | ||
508 | '(' + | ||
509 | 'select "videoId" FROM "videoStreamingPlaylist" ' + | ||
510 | 'INNER JOIN "videoRedundancy" ON "videoRedundancy"."videoStreamingPlaylistId" = "videoStreamingPlaylist".id' + | ||
511 | redundancySqlSuffix + | ||
512 | ')' | ||
513 | ) | ||
514 | } | ||
515 | } | ||
516 | ] | ||
517 | }, | ||
518 | |||
519 | videosWhere | ||
520 | ] | ||
521 | } | ||
522 | |||
523 | // /!\ On video model /!\ | ||
524 | const findOptions = { | ||
525 | offset: start, | ||
526 | limit: count, | ||
527 | order: getSort(sort), | ||
528 | include: [ | ||
529 | { | ||
530 | required: false, | ||
531 | model: VideoFileModel.unscoped(), | ||
532 | include: [ | ||
533 | { | ||
534 | model: VideoRedundancyModel.unscoped(), | ||
535 | required: false, | ||
536 | where: redundancyWhere | ||
537 | } | ||
538 | ] | ||
539 | }, | ||
540 | { | ||
541 | required: false, | ||
542 | model: VideoStreamingPlaylistModel.unscoped(), | ||
543 | include: [ | ||
544 | { | ||
545 | model: VideoRedundancyModel.unscoped(), | ||
546 | required: false, | ||
547 | where: redundancyWhere | ||
548 | }, | ||
549 | { | ||
550 | model: VideoFileModel.unscoped(), | ||
551 | required: false | ||
552 | } | ||
553 | ] | ||
554 | } | ||
555 | ], | ||
556 | where: videoFilterWhere | ||
557 | } | ||
558 | |||
559 | // /!\ On video model /!\ | ||
560 | const countOptions = { | ||
561 | where: videoFilterWhere | ||
562 | } | ||
563 | |||
564 | return Promise.all([ | ||
565 | VideoModel.findAll(findOptions), | ||
566 | |||
567 | VideoModel.count(countOptions) | ||
568 | ]).then(([ data, total ]) => ({ total, data })) | ||
569 | } | ||
570 | |||
571 | static async getStats (strategy: VideoRedundancyStrategyWithManual) { | ||
451 | const actor = await getServerActor() | 572 | const actor = await getServerActor() |
452 | 573 | ||
453 | const query: FindOptions = { | 574 | const query: FindOptions = { |
@@ -471,11 +592,58 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
471 | } | 592 | } |
472 | 593 | ||
473 | return VideoRedundancyModel.findOne(query) | 594 | return VideoRedundancyModel.findOne(query) |
474 | .then((r: any) => ({ | 595 | .then((r: any) => ({ |
475 | totalUsed: parseAggregateResult(r.totalUsed), | 596 | totalUsed: parseAggregateResult(r.totalUsed), |
476 | totalVideos: r.totalVideos, | 597 | totalVideos: r.totalVideos, |
477 | totalVideoFiles: r.totalVideoFiles | 598 | totalVideoFiles: r.totalVideoFiles |
478 | })) | 599 | })) |
600 | } | ||
601 | |||
602 | static toFormattedJSONStatic (video: MVideoForRedundancyAPI): VideoRedundancy { | ||
603 | const filesRedundancies: FileRedundancyInformation[] = [] | ||
604 | const streamingPlaylistsRedundancies: StreamingPlaylistRedundancyInformation[] = [] | ||
605 | |||
606 | for (const file of video.VideoFiles) { | ||
607 | for (const redundancy of file.RedundancyVideos) { | ||
608 | filesRedundancies.push({ | ||
609 | id: redundancy.id, | ||
610 | fileUrl: redundancy.fileUrl, | ||
611 | strategy: redundancy.strategy, | ||
612 | createdAt: redundancy.createdAt, | ||
613 | updatedAt: redundancy.updatedAt, | ||
614 | expiresOn: redundancy.expiresOn, | ||
615 | size: file.size | ||
616 | }) | ||
617 | } | ||
618 | } | ||
619 | |||
620 | for (const playlist of video.VideoStreamingPlaylists) { | ||
621 | const size = playlist.VideoFiles.reduce((a, b) => a + b.size, 0) | ||
622 | |||
623 | for (const redundancy of playlist.RedundancyVideos) { | ||
624 | streamingPlaylistsRedundancies.push({ | ||
625 | id: redundancy.id, | ||
626 | fileUrl: redundancy.fileUrl, | ||
627 | strategy: redundancy.strategy, | ||
628 | createdAt: redundancy.createdAt, | ||
629 | updatedAt: redundancy.updatedAt, | ||
630 | expiresOn: redundancy.expiresOn, | ||
631 | size | ||
632 | }) | ||
633 | } | ||
634 | } | ||
635 | |||
636 | return { | ||
637 | id: video.id, | ||
638 | name: video.name, | ||
639 | url: video.url, | ||
640 | uuid: video.uuid, | ||
641 | |||
642 | redundancies: { | ||
643 | files: filesRedundancies, | ||
644 | streamingPlaylists: streamingPlaylistsRedundancies | ||
645 | } | ||
646 | } | ||
479 | } | 647 | } |
480 | 648 | ||
481 | getVideo () { | 649 | getVideo () { |
@@ -494,7 +662,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
494 | id: this.url, | 662 | id: this.url, |
495 | type: 'CacheFile' as 'CacheFile', | 663 | type: 'CacheFile' as 'CacheFile', |
496 | object: this.VideoStreamingPlaylist.Video.url, | 664 | object: this.VideoStreamingPlaylist.Video.url, |
497 | expires: this.expiresOn.toISOString(), | 665 | expires: this.expiresOn ? this.expiresOn.toISOString() : null, |
498 | url: { | 666 | url: { |
499 | type: 'Link', | 667 | type: 'Link', |
500 | mediaType: 'application/x-mpegURL', | 668 | mediaType: 'application/x-mpegURL', |
@@ -507,10 +675,10 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
507 | id: this.url, | 675 | id: this.url, |
508 | type: 'CacheFile' as 'CacheFile', | 676 | type: 'CacheFile' as 'CacheFile', |
509 | object: this.VideoFile.Video.url, | 677 | object: this.VideoFile.Video.url, |
510 | expires: this.expiresOn.toISOString(), | 678 | expires: this.expiresOn ? this.expiresOn.toISOString() : null, |
511 | url: { | 679 | url: { |
512 | type: 'Link', | 680 | type: 'Link', |
513 | mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[ this.VideoFile.extname ] as any, | 681 | mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[this.VideoFile.extname] as any, |
514 | href: this.fileUrl, | 682 | href: this.fileUrl, |
515 | height: this.VideoFile.resolution, | 683 | height: this.VideoFile.resolution, |
516 | size: this.VideoFile.size, | 684 | size: this.VideoFile.size, |
@@ -525,7 +693,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
525 | 693 | ||
526 | const notIn = literal( | 694 | const notIn = literal( |
527 | '(' + | 695 | '(' + |
528 | `SELECT "videoFileId" FROM "videoRedundancy" WHERE "actorId" = ${actor.id} AND "videoFileId" IS NOT NULL` + | 696 | `SELECT "videoFileId" FROM "videoRedundancy" WHERE "actorId" = ${actor.id} AND "videoFileId" IS NOT NULL` + |
529 | ')' | 697 | ')' |
530 | ) | 698 | ) |
531 | 699 | ||
@@ -535,7 +703,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
535 | required: true, | 703 | required: true, |
536 | where: { | 704 | where: { |
537 | id: { | 705 | id: { |
538 | [ Op.notIn ]: notIn | 706 | [Op.notIn]: notIn |
539 | } | 707 | } |
540 | } | 708 | } |
541 | } | 709 | } |
diff --git a/server/models/server/plugin.ts b/server/models/server/plugin.ts index d094da1f5..95774a467 100644 --- a/server/models/server/plugin.ts +++ b/server/models/server/plugin.ts | |||
@@ -189,10 +189,10 @@ export class PluginModel extends Model<PluginModel> { | |||
189 | } | 189 | } |
190 | 190 | ||
191 | static listForApi (options: { | 191 | static listForApi (options: { |
192 | pluginType?: PluginType, | 192 | pluginType?: PluginType |
193 | uninstalled?: boolean, | 193 | uninstalled?: boolean |
194 | start: number, | 194 | start: number |
195 | count: number, | 195 | count: number |
196 | sort: string | 196 | sort: string |
197 | }) { | 197 | }) { |
198 | const { uninstalled = false } = options | 198 | const { uninstalled = false } = options |
diff --git a/server/models/server/server-blocklist.ts b/server/models/server/server-blocklist.ts index b88df4fd5..883ae47ab 100644 --- a/server/models/server/server-blocklist.ts +++ b/server/models/server/server-blocklist.ts | |||
@@ -81,7 +81,7 @@ export class ServerBlocklistModel extends Model<ServerBlocklistModel> { | |||
81 | attributes: [ 'accountId', 'id' ], | 81 | attributes: [ 'accountId', 'id' ], |
82 | where: { | 82 | where: { |
83 | accountId: { | 83 | accountId: { |
84 | [Op.in]: accountIds // FIXME: sequelize ANY seems broken | 84 | [Op.in]: accountIds |
85 | }, | 85 | }, |
86 | targetServerId | 86 | targetServerId |
87 | }, | 87 | }, |
diff --git a/server/models/utils.ts b/server/models/utils.ts index f89b80011..f7afb8d4b 100644 --- a/server/models/utils.ts +++ b/server/models/utils.ts | |||
@@ -67,7 +67,7 @@ function getVideoSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): Or | |||
67 | function getBlacklistSort (model: any, value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] { | 67 | function getBlacklistSort (model: any, value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] { |
68 | const [ firstSort ] = getSort(value) | 68 | const [ firstSort ] = getSort(value) |
69 | 69 | ||
70 | if (model) return [ [ literal(`"${model}.${firstSort[ 0 ]}" ${firstSort[ 1 ]}`) ], lastSort ] as any[] // FIXME: typings | 70 | if (model) return [ [ literal(`"${model}.${firstSort[0]}" ${firstSort[1]}`) ], lastSort ] as any[] // FIXME: typings |
71 | return [ firstSort, lastSort ] | 71 | return [ firstSort, lastSort ] |
72 | } | 72 | } |
73 | 73 | ||
@@ -139,7 +139,7 @@ function buildServerIdsFollowedBy (actorId: any) { | |||
139 | 'SELECT "actor"."serverId" FROM "actorFollow" ' + | 139 | 'SELECT "actor"."serverId" FROM "actorFollow" ' + |
140 | 'INNER JOIN "actor" ON actor.id = "actorFollow"."targetActorId" ' + | 140 | 'INNER JOIN "actor" ON actor.id = "actorFollow"."targetActorId" ' + |
141 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + | 141 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + |
142 | ')' | 142 | ')' |
143 | } | 143 | } |
144 | 144 | ||
145 | function buildWhereIdOrUUID (id: number | string) { | 145 | function buildWhereIdOrUUID (id: number | string) { |
diff --git a/server/models/video/thumbnail.ts b/server/models/video/thumbnail.ts index 3b011b1d2..e396784d2 100644 --- a/server/models/video/thumbnail.ts +++ b/server/models/video/thumbnail.ts | |||
@@ -19,6 +19,8 @@ import { CONFIG } from '../../initializers/config' | |||
19 | import { VideoModel } from './video' | 19 | import { VideoModel } from './video' |
20 | import { VideoPlaylistModel } from './video-playlist' | 20 | import { VideoPlaylistModel } from './video-playlist' |
21 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' | 21 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' |
22 | import { MVideoAccountLight } from '@server/typings/models' | ||
23 | import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub' | ||
22 | 24 | ||
23 | @Table({ | 25 | @Table({ |
24 | tableName: 'thumbnail', | 26 | tableName: 'thumbnail', |
@@ -90,7 +92,7 @@ export class ThumbnailModel extends Model<ThumbnailModel> { | |||
90 | @UpdatedAt | 92 | @UpdatedAt |
91 | updatedAt: Date | 93 | updatedAt: Date |
92 | 94 | ||
93 | private static types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = { | 95 | private static readonly types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = { |
94 | [ThumbnailType.MINIATURE]: { | 96 | [ThumbnailType.MINIATURE]: { |
95 | label: 'miniature', | 97 | label: 'miniature', |
96 | directory: CONFIG.STORAGE.THUMBNAILS_DIR, | 98 | directory: CONFIG.STORAGE.THUMBNAILS_DIR, |
@@ -126,11 +128,14 @@ export class ThumbnailModel extends Model<ThumbnailModel> { | |||
126 | return videoUUID + '.jpg' | 128 | return videoUUID + '.jpg' |
127 | } | 129 | } |
128 | 130 | ||
129 | getFileUrl (isLocal: boolean) { | 131 | getFileUrl (video: MVideoAccountLight) { |
130 | if (isLocal === false) return this.fileUrl | 132 | const staticPath = ThumbnailModel.types[this.type].staticPath + this.filename |
131 | 133 | ||
132 | const staticPath = ThumbnailModel.types[this.type].staticPath | 134 | if (video.isOwned()) return WEBSERVER.URL + staticPath |
133 | return WEBSERVER.URL + staticPath + this.filename | 135 | if (this.fileUrl) return this.fileUrl |
136 | |||
137 | // Fallback if we don't have a file URL | ||
138 | return buildRemoteVideoBaseUrl(video, staticPath) | ||
134 | } | 139 | } |
135 | 140 | ||
136 | getPath () { | 141 | getPath () { |
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts index 3636db18d..da8c1577c 100644 --- a/server/models/video/video-abuse.ts +++ b/server/models/video/video-abuse.ts | |||
@@ -87,9 +87,9 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
87 | } | 87 | } |
88 | 88 | ||
89 | static listForApi (parameters: { | 89 | static listForApi (parameters: { |
90 | start: number, | 90 | start: number |
91 | count: number, | 91 | count: number |
92 | sort: string, | 92 | sort: string |
93 | serverAccountId: number | 93 | serverAccountId: number |
94 | user?: MUserAccountId | 94 | user?: MUserAccountId |
95 | }) { | 95 | }) { |
diff --git a/server/models/video/video-caption.ts b/server/models/video/video-caption.ts index eeb2a4afd..59d3e1050 100644 --- a/server/models/video/video-caption.ts +++ b/server/models/video/video-caption.ts | |||
@@ -5,6 +5,7 @@ import { | |||
5 | BelongsTo, | 5 | BelongsTo, |
6 | Column, | 6 | Column, |
7 | CreatedAt, | 7 | CreatedAt, |
8 | DataType, | ||
8 | ForeignKey, | 9 | ForeignKey, |
9 | Is, | 10 | Is, |
10 | Model, | 11 | Model, |
@@ -16,13 +17,14 @@ import { buildWhereIdOrUUID, throwIfNotValid } from '../utils' | |||
16 | import { VideoModel } from './video' | 17 | import { VideoModel } from './video' |
17 | import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' | 18 | import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' |
18 | import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' | 19 | import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' |
19 | import { LAZY_STATIC_PATHS, VIDEO_LANGUAGES } from '../../initializers/constants' | 20 | import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, VIDEO_LANGUAGES, WEBSERVER } from '../../initializers/constants' |
20 | import { join } from 'path' | 21 | import { join } from 'path' |
21 | import { logger } from '../../helpers/logger' | 22 | import { logger } from '../../helpers/logger' |
22 | import { remove } from 'fs-extra' | 23 | import { remove } from 'fs-extra' |
23 | import { CONFIG } from '../../initializers/config' | 24 | import { CONFIG } from '../../initializers/config' |
24 | import * as Bluebird from 'bluebird' | 25 | import * as Bluebird from 'bluebird' |
25 | import { MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/typings/models' | 26 | import { MVideoAccountLight, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/typings/models' |
27 | import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub' | ||
26 | 28 | ||
27 | export enum ScopeNames { | 29 | export enum ScopeNames { |
28 | WITH_VIDEO_UUID_AND_REMOTE = 'WITH_VIDEO_UUID_AND_REMOTE' | 30 | WITH_VIDEO_UUID_AND_REMOTE = 'WITH_VIDEO_UUID_AND_REMOTE' |
@@ -64,6 +66,10 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> { | |||
64 | @Column | 66 | @Column |
65 | language: string | 67 | language: string |
66 | 68 | ||
69 | @AllowNull(true) | ||
70 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.COMMONS.URL.max)) | ||
71 | fileUrl: string | ||
72 | |||
67 | @ForeignKey(() => VideoModel) | 73 | @ForeignKey(() => VideoModel) |
68 | @Column | 74 | @Column |
69 | videoId: number | 75 | videoId: number |
@@ -114,13 +120,14 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> { | |||
114 | return VideoCaptionModel.findOne(query) | 120 | return VideoCaptionModel.findOne(query) |
115 | } | 121 | } |
116 | 122 | ||
117 | static insertOrReplaceLanguage (videoId: number, language: string, transaction: Transaction) { | 123 | static insertOrReplaceLanguage (videoId: number, language: string, fileUrl: string, transaction: Transaction) { |
118 | const values = { | 124 | const values = { |
119 | videoId, | 125 | videoId, |
120 | language | 126 | language, |
127 | fileUrl | ||
121 | } | 128 | } |
122 | 129 | ||
123 | return (VideoCaptionModel.upsert<VideoCaptionModel>(values, { transaction, returning: true }) as any) // FIXME: typings | 130 | return VideoCaptionModel.upsert(values, { transaction, returning: true }) |
124 | .then(([ caption ]) => caption) | 131 | .then(([ caption ]) => caption) |
125 | } | 132 | } |
126 | 133 | ||
@@ -175,4 +182,14 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> { | |||
175 | removeCaptionFile (this: MVideoCaptionFormattable) { | 182 | removeCaptionFile (this: MVideoCaptionFormattable) { |
176 | return remove(CONFIG.STORAGE.CAPTIONS_DIR + this.getCaptionName()) | 183 | return remove(CONFIG.STORAGE.CAPTIONS_DIR + this.getCaptionName()) |
177 | } | 184 | } |
185 | |||
186 | getFileUrl (video: MVideoAccountLight) { | ||
187 | if (!this.Video) this.Video = video as VideoModel | ||
188 | |||
189 | if (video.isOwned()) return WEBSERVER.URL + this.getCaptionStaticPath() | ||
190 | if (this.fileUrl) return this.fileUrl | ||
191 | |||
192 | // Fallback if we don't have a file URL | ||
193 | return buildRemoteVideoBaseUrl(video, this.getCaptionStaticPath()) | ||
194 | } | ||
178 | } | 195 | } |
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index e10adcb3a..835216671 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -30,7 +30,7 @@ import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttr | |||
30 | import { VideoModel } from './video' | 30 | import { VideoModel } from './video' |
31 | import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' | 31 | import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' |
32 | import { ServerModel } from '../server/server' | 32 | import { ServerModel } from '../server/server' |
33 | import { FindOptions, ModelIndexesOptions, Op } from 'sequelize' | 33 | import { FindOptions, Op } from 'sequelize' |
34 | import { AvatarModel } from '../avatar/avatar' | 34 | import { AvatarModel } from '../avatar/avatar' |
35 | import { VideoPlaylistModel } from './video-playlist' | 35 | import { VideoPlaylistModel } from './video-playlist' |
36 | import * as Bluebird from 'bluebird' | 36 | import * as Bluebird from 'bluebird' |
@@ -43,18 +43,6 @@ import { | |||
43 | MChannelSummaryFormattable | 43 | MChannelSummaryFormattable |
44 | } from '../../typings/models/video' | 44 | } from '../../typings/models/video' |
45 | 45 | ||
46 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | ||
47 | const indexes: ModelIndexesOptions[] = [ | ||
48 | buildTrigramSearchIndex('video_channel_name_trigram', 'name'), | ||
49 | |||
50 | { | ||
51 | fields: [ 'accountId' ] | ||
52 | }, | ||
53 | { | ||
54 | fields: [ 'actorId' ] | ||
55 | } | ||
56 | ] | ||
57 | |||
58 | export enum ScopeNames { | 46 | export enum ScopeNames { |
59 | FOR_API = 'FOR_API', | 47 | FOR_API = 'FOR_API', |
60 | WITH_ACCOUNT = 'WITH_ACCOUNT', | 48 | WITH_ACCOUNT = 'WITH_ACCOUNT', |
@@ -133,7 +121,7 @@ export type SummaryOptions = { | |||
133 | }, | 121 | }, |
134 | { | 122 | { |
135 | serverId: { | 123 | serverId: { |
136 | [ Op.in ]: Sequelize.literal(inQueryInstanceFollow) | 124 | [Op.in]: Sequelize.literal(inQueryInstanceFollow) |
137 | } | 125 | } |
138 | } | 126 | } |
139 | ] | 127 | ] |
@@ -176,7 +164,16 @@ export type SummaryOptions = { | |||
176 | })) | 164 | })) |
177 | @Table({ | 165 | @Table({ |
178 | tableName: 'videoChannel', | 166 | tableName: 'videoChannel', |
179 | indexes | 167 | indexes: [ |
168 | buildTrigramSearchIndex('video_channel_name_trigram', 'name'), | ||
169 | |||
170 | { | ||
171 | fields: [ 'accountId' ] | ||
172 | }, | ||
173 | { | ||
174 | fields: [ 'actorId' ] | ||
175 | } | ||
176 | ] | ||
180 | }) | 177 | }) |
181 | export class VideoChannelModel extends Model<VideoChannelModel> { | 178 | export class VideoChannelModel extends Model<VideoChannelModel> { |
182 | 179 | ||
@@ -351,9 +348,9 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
351 | } | 348 | } |
352 | 349 | ||
353 | static listByAccount (options: { | 350 | static listByAccount (options: { |
354 | accountId: number, | 351 | accountId: number |
355 | start: number, | 352 | start: number |
356 | count: number, | 353 | count: number |
357 | sort: string | 354 | sort: string |
358 | }) { | 355 | }) { |
359 | const query = { | 356 | const query = { |
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index fb4d16b4d..b33c33d5e 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts | |||
@@ -257,10 +257,10 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
257 | } | 257 | } |
258 | 258 | ||
259 | static async listThreadsForApi (parameters: { | 259 | static async listThreadsForApi (parameters: { |
260 | videoId: number, | 260 | videoId: number |
261 | start: number, | 261 | start: number |
262 | count: number, | 262 | count: number |
263 | sort: string, | 263 | sort: string |
264 | user?: MUserAccountId | 264 | user?: MUserAccountId |
265 | }) { | 265 | }) { |
266 | const { videoId, start, count, sort, user } = parameters | 266 | const { videoId, start, count, sort, user } = parameters |
@@ -300,8 +300,8 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
300 | } | 300 | } |
301 | 301 | ||
302 | static async listThreadCommentsForApi (parameters: { | 302 | static async listThreadCommentsForApi (parameters: { |
303 | videoId: number, | 303 | videoId: number |
304 | threadId: number, | 304 | threadId: number |
305 | user?: MUserAccountId | 305 | user?: MUserAccountId |
306 | }) { | 306 | }) { |
307 | const { videoId, threadId, user } = parameters | 307 | const { videoId, threadId, user } = parameters |
@@ -314,7 +314,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
314 | order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ] as Order, | 314 | order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ] as Order, |
315 | where: { | 315 | where: { |
316 | videoId, | 316 | videoId, |
317 | [ Op.or ]: [ | 317 | [Op.or]: [ |
318 | { id: threadId }, | 318 | { id: threadId }, |
319 | { originCommentId: threadId } | 319 | { originCommentId: threadId } |
320 | ], | 320 | ], |
@@ -346,7 +346,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
346 | order: [ [ 'createdAt', order ] ] as Order, | 346 | order: [ [ 'createdAt', order ] ] as Order, |
347 | where: { | 347 | where: { |
348 | id: { | 348 | id: { |
349 | [ Op.in ]: Sequelize.literal('(' + | 349 | [Op.in]: Sequelize.literal('(' + |
350 | 'WITH RECURSIVE children (id, "inReplyToCommentId") AS ( ' + | 350 | 'WITH RECURSIVE children (id, "inReplyToCommentId") AS ( ' + |
351 | `SELECT id, "inReplyToCommentId" FROM "videoComment" WHERE id = ${comment.id} ` + | 351 | `SELECT id, "inReplyToCommentId" FROM "videoComment" WHERE id = ${comment.id} ` + |
352 | 'UNION ' + | 352 | 'UNION ' + |
@@ -355,7 +355,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
355 | ') ' + | 355 | ') ' + |
356 | 'SELECT id FROM children' + | 356 | 'SELECT id FROM children' + |
357 | ')'), | 357 | ')'), |
358 | [ Op.ne ]: comment.id | 358 | [Op.ne]: comment.id |
359 | } | 359 | } |
360 | }, | 360 | }, |
361 | transaction: t | 361 | transaction: t |
@@ -461,7 +461,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
461 | } | 461 | } |
462 | 462 | ||
463 | isDeleted () { | 463 | isDeleted () { |
464 | return null !== this.deletedAt | 464 | return this.deletedAt !== null |
465 | } | 465 | } |
466 | 466 | ||
467 | extractMentions () { | 467 | extractMentions () { |
diff --git a/server/models/video/video-format-utils.ts b/server/models/video/video-format-utils.ts index 67395e5c0..1fa66fd63 100644 --- a/server/models/video/video-format-utils.ts +++ b/server/models/video/video-format-utils.ts | |||
@@ -27,12 +27,13 @@ import { generateMagnetUri } from '@server/helpers/webtorrent' | |||
27 | export type VideoFormattingJSONOptions = { | 27 | export type VideoFormattingJSONOptions = { |
28 | completeDescription?: boolean | 28 | completeDescription?: boolean |
29 | additionalAttributes: { | 29 | additionalAttributes: { |
30 | state?: boolean, | 30 | state?: boolean |
31 | waitTranscoding?: boolean, | 31 | waitTranscoding?: boolean |
32 | scheduledUpdate?: boolean, | 32 | scheduledUpdate?: boolean |
33 | blacklistInfo?: boolean | 33 | blacklistInfo?: boolean |
34 | } | 34 | } |
35 | } | 35 | } |
36 | |||
36 | function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFormattingJSONOptions): Video { | 37 | function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFormattingJSONOptions): Video { |
37 | const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined | 38 | const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined |
38 | 39 | ||
@@ -181,12 +182,10 @@ function videoFilesModelToFormattedJSON ( | |||
181 | ): VideoFile[] { | 182 | ): VideoFile[] { |
182 | return videoFiles | 183 | return videoFiles |
183 | .map(videoFile => { | 184 | .map(videoFile => { |
184 | let resolutionLabel = videoFile.resolution + 'p' | ||
185 | |||
186 | return { | 185 | return { |
187 | resolution: { | 186 | resolution: { |
188 | id: videoFile.resolution, | 187 | id: videoFile.resolution, |
189 | label: resolutionLabel | 188 | label: videoFile.resolution + 'p' |
190 | }, | 189 | }, |
191 | magnetUri: generateMagnetUri(model, videoFile, baseUrlHttp, baseUrlWs), | 190 | magnetUri: generateMagnetUri(model, videoFile, baseUrlHttp, baseUrlWs), |
192 | size: videoFile.size, | 191 | size: videoFile.size, |
@@ -214,7 +213,7 @@ function addVideoFilesInAPAcc ( | |||
214 | for (const file of files) { | 213 | for (const file of files) { |
215 | acc.push({ | 214 | acc.push({ |
216 | type: 'Link', | 215 | type: 'Link', |
217 | mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[ file.extname ] as any, | 216 | mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[file.extname] as any, |
218 | href: model.getVideoFileUrl(file, baseUrlHttp), | 217 | href: model.getVideoFileUrl(file, baseUrlHttp), |
219 | height: file.resolution, | 218 | height: file.resolution, |
220 | size: file.size, | 219 | size: file.size, |
@@ -282,10 +281,8 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject { | |||
282 | addVideoFilesInAPAcc(url, video, baseUrlHttp, baseUrlWs, video.VideoFiles || []) | 281 | addVideoFilesInAPAcc(url, video, baseUrlHttp, baseUrlWs, video.VideoFiles || []) |
283 | 282 | ||
284 | for (const playlist of (video.VideoStreamingPlaylists || [])) { | 283 | for (const playlist of (video.VideoStreamingPlaylists || [])) { |
285 | let tag: ActivityTagObject[] | 284 | const tag = playlist.p2pMediaLoaderInfohashes |
286 | 285 | .map(i => ({ type: 'Infohash' as 'Infohash', name: i })) as ActivityTagObject[] | |
287 | tag = playlist.p2pMediaLoaderInfohashes | ||
288 | .map(i => ({ type: 'Infohash' as 'Infohash', name: i })) | ||
289 | tag.push({ | 286 | tag.push({ |
290 | type: 'Link', | 287 | type: 'Link', |
291 | name: 'sha256', | 288 | name: 'sha256', |
@@ -308,11 +305,12 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject { | |||
308 | for (const caption of video.VideoCaptions) { | 305 | for (const caption of video.VideoCaptions) { |
309 | subtitleLanguage.push({ | 306 | subtitleLanguage.push({ |
310 | identifier: caption.language, | 307 | identifier: caption.language, |
311 | name: VideoCaptionModel.getLanguageLabel(caption.language) | 308 | name: VideoCaptionModel.getLanguageLabel(caption.language), |
309 | url: caption.getFileUrl(video) | ||
312 | }) | 310 | }) |
313 | } | 311 | } |
314 | 312 | ||
315 | const miniature = video.getMiniature() | 313 | const icons = [ video.getMiniature(), video.getPreview() ] |
316 | 314 | ||
317 | return { | 315 | return { |
318 | type: 'Video' as 'Video', | 316 | type: 'Video' as 'Video', |
@@ -337,13 +335,13 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject { | |||
337 | content: video.getTruncatedDescription(), | 335 | content: video.getTruncatedDescription(), |
338 | support: video.support, | 336 | support: video.support, |
339 | subtitleLanguage, | 337 | subtitleLanguage, |
340 | icon: { | 338 | icon: icons.map(i => ({ |
341 | type: 'Image', | 339 | type: 'Image', |
342 | url: miniature.getFileUrl(video.isOwned()), | 340 | url: i.getFileUrl(video), |
343 | mediaType: 'image/jpeg', | 341 | mediaType: 'image/jpeg', |
344 | width: miniature.width, | 342 | width: i.width, |
345 | height: miniature.height | 343 | height: i.height |
346 | }, | 344 | })), |
347 | url, | 345 | url, |
348 | likes: getVideoLikesActivityPubUrl(video), | 346 | likes: getVideoLikesActivityPubUrl(video), |
349 | dislikes: getVideoDislikesActivityPubUrl(video), | 347 | dislikes: getVideoDislikesActivityPubUrl(video), |
diff --git a/server/models/video/video-playlist-element.ts b/server/models/video/video-playlist-element.ts index f2d71357f..4ba16f5fd 100644 --- a/server/models/video/video-playlist-element.ts +++ b/server/models/video/video-playlist-element.ts | |||
@@ -120,10 +120,10 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
120 | } | 120 | } |
121 | 121 | ||
122 | static listForApi (options: { | 122 | static listForApi (options: { |
123 | start: number, | 123 | start: number |
124 | count: number, | 124 | count: number |
125 | videoPlaylistId: number, | 125 | videoPlaylistId: number |
126 | serverAccount: AccountModel, | 126 | serverAccount: AccountModel |
127 | user?: MUserAccountId | 127 | user?: MUserAccountId |
128 | }) { | 128 | }) { |
129 | const accountIds = [ options.serverAccount.id ] | 129 | const accountIds = [ options.serverAccount.id ] |
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts index bcdda36e5..4ca17ebec 100644 --- a/server/models/video/video-playlist.ts +++ b/server/models/video/video-playlist.ts | |||
@@ -68,12 +68,12 @@ type AvailableForListOptions = { | |||
68 | type?: VideoPlaylistType | 68 | type?: VideoPlaylistType |
69 | accountId?: number | 69 | accountId?: number |
70 | videoChannelId?: number | 70 | videoChannelId?: number |
71 | listMyPlaylists?: boolean, | 71 | listMyPlaylists?: boolean |
72 | search?: string | 72 | search?: string |
73 | } | 73 | } |
74 | 74 | ||
75 | @Scopes(() => ({ | 75 | @Scopes(() => ({ |
76 | [ ScopeNames.WITH_THUMBNAIL ]: { | 76 | [ScopeNames.WITH_THUMBNAIL]: { |
77 | include: [ | 77 | include: [ |
78 | { | 78 | { |
79 | model: ThumbnailModel, | 79 | model: ThumbnailModel, |
@@ -81,7 +81,7 @@ type AvailableForListOptions = { | |||
81 | } | 81 | } |
82 | ] | 82 | ] |
83 | }, | 83 | }, |
84 | [ ScopeNames.WITH_VIDEOS_LENGTH ]: { | 84 | [ScopeNames.WITH_VIDEOS_LENGTH]: { |
85 | attributes: { | 85 | attributes: { |
86 | include: [ | 86 | include: [ |
87 | [ | 87 | [ |
@@ -91,7 +91,7 @@ type AvailableForListOptions = { | |||
91 | ] | 91 | ] |
92 | } | 92 | } |
93 | } as FindOptions, | 93 | } as FindOptions, |
94 | [ ScopeNames.WITH_ACCOUNT ]: { | 94 | [ScopeNames.WITH_ACCOUNT]: { |
95 | include: [ | 95 | include: [ |
96 | { | 96 | { |
97 | model: AccountModel, | 97 | model: AccountModel, |
@@ -99,7 +99,7 @@ type AvailableForListOptions = { | |||
99 | } | 99 | } |
100 | ] | 100 | ] |
101 | }, | 101 | }, |
102 | [ ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY ]: { | 102 | [ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY]: { |
103 | include: [ | 103 | include: [ |
104 | { | 104 | { |
105 | model: AccountModel.scope(AccountScopeNames.SUMMARY), | 105 | model: AccountModel.scope(AccountScopeNames.SUMMARY), |
@@ -111,7 +111,7 @@ type AvailableForListOptions = { | |||
111 | } | 111 | } |
112 | ] | 112 | ] |
113 | }, | 113 | }, |
114 | [ ScopeNames.WITH_ACCOUNT_AND_CHANNEL ]: { | 114 | [ScopeNames.WITH_ACCOUNT_AND_CHANNEL]: { |
115 | include: [ | 115 | include: [ |
116 | { | 116 | { |
117 | model: AccountModel, | 117 | model: AccountModel, |
@@ -123,7 +123,7 @@ type AvailableForListOptions = { | |||
123 | } | 123 | } |
124 | ] | 124 | ] |
125 | }, | 125 | }, |
126 | [ ScopeNames.AVAILABLE_FOR_LIST ]: (options: AvailableForListOptions) => { | 126 | [ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => { |
127 | 127 | ||
128 | let whereActor: WhereOptions = {} | 128 | let whereActor: WhereOptions = {} |
129 | 129 | ||
@@ -138,13 +138,13 @@ type AvailableForListOptions = { | |||
138 | const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId) | 138 | const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId) |
139 | 139 | ||
140 | whereActor = { | 140 | whereActor = { |
141 | [ Op.or ]: [ | 141 | [Op.or]: [ |
142 | { | 142 | { |
143 | serverId: null | 143 | serverId: null |
144 | }, | 144 | }, |
145 | { | 145 | { |
146 | serverId: { | 146 | serverId: { |
147 | [ Op.in ]: literal(inQueryInstanceFollow) | 147 | [Op.in]: literal(inQueryInstanceFollow) |
148 | } | 148 | } |
149 | } | 149 | } |
150 | ] | 150 | ] |
@@ -172,7 +172,7 @@ type AvailableForListOptions = { | |||
172 | if (options.search) { | 172 | if (options.search) { |
173 | whereAnd.push({ | 173 | whereAnd.push({ |
174 | name: { | 174 | name: { |
175 | [ Op.iLike ]: '%' + options.search + '%' | 175 | [Op.iLike]: '%' + options.search + '%' |
176 | } | 176 | } |
177 | }) | 177 | }) |
178 | } | 178 | } |
@@ -299,13 +299,13 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
299 | 299 | ||
300 | static listForApi (options: { | 300 | static listForApi (options: { |
301 | followerActorId: number | 301 | followerActorId: number |
302 | start: number, | 302 | start: number |
303 | count: number, | 303 | count: number |
304 | sort: string, | 304 | sort: string |
305 | type?: VideoPlaylistType, | 305 | type?: VideoPlaylistType |
306 | accountId?: number, | 306 | accountId?: number |
307 | videoChannelId?: number, | 307 | videoChannelId?: number |
308 | listMyPlaylists?: boolean, | 308 | listMyPlaylists?: boolean |
309 | search?: string | 309 | search?: string |
310 | }) { | 310 | }) { |
311 | const query = { | 311 | const query = { |
@@ -369,7 +369,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
369 | model: VideoPlaylistElementModel.unscoped(), | 369 | model: VideoPlaylistElementModel.unscoped(), |
370 | where: { | 370 | where: { |
371 | videoId: { | 371 | videoId: { |
372 | [Op.in]: videoIds // FIXME: sequelize ANY seems broken | 372 | [Op.in]: videoIds |
373 | } | 373 | } |
374 | }, | 374 | }, |
375 | required: true | 375 | required: true |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index eacffe186..1ec8d717e 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -1,18 +1,7 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { maxBy, minBy } from 'lodash' | 2 | import { maxBy, minBy } from 'lodash' |
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import { | 4 | import { CountOptions, FindOptions, IncludeOptions, Op, QueryTypes, ScopeOptions, Sequelize, Transaction, WhereOptions } from 'sequelize' |
5 | CountOptions, | ||
6 | FindOptions, | ||
7 | IncludeOptions, | ||
8 | ModelIndexesOptions, | ||
9 | Op, | ||
10 | QueryTypes, | ||
11 | ScopeOptions, | ||
12 | Sequelize, | ||
13 | Transaction, | ||
14 | WhereOptions | ||
15 | } from 'sequelize' | ||
16 | import { | 5 | import { |
17 | AllowNull, | 6 | AllowNull, |
18 | BeforeDestroy, | 7 | BeforeDestroy, |
@@ -136,8 +125,7 @@ import { | |||
136 | MVideoThumbnailBlacklist, | 125 | MVideoThumbnailBlacklist, |
137 | MVideoWithAllFiles, | 126 | MVideoWithAllFiles, |
138 | MVideoWithFile, | 127 | MVideoWithFile, |
139 | MVideoWithRights, | 128 | MVideoWithRights |
140 | MStreamingPlaylistFiles | ||
141 | } from '../../typings/models' | 129 | } from '../../typings/models' |
142 | import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../typings/models/video/video-file' | 130 | import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../typings/models/video/video-file' |
143 | import { MThumbnail } from '../../typings/models/video/thumbnail' | 131 | import { MThumbnail } from '../../typings/models/video/thumbnail' |
@@ -145,74 +133,6 @@ import { VideoFile } from '@shared/models/videos/video-file.model' | |||
145 | import { getHLSDirectory, getTorrentFileName, getTorrentFilePath, getVideoFilename, getVideoFilePath } from '@server/lib/video-paths' | 133 | import { getHLSDirectory, getTorrentFileName, getTorrentFilePath, getVideoFilename, getVideoFilePath } from '@server/lib/video-paths' |
146 | import validator from 'validator' | 134 | import validator from 'validator' |
147 | 135 | ||
148 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | ||
149 | const indexes: (ModelIndexesOptions & { where?: WhereOptions })[] = [ | ||
150 | buildTrigramSearchIndex('video_name_trigram', 'name'), | ||
151 | |||
152 | { fields: [ 'createdAt' ] }, | ||
153 | { | ||
154 | fields: [ | ||
155 | { name: 'publishedAt', order: 'DESC' }, | ||
156 | { name: 'id', order: 'ASC' } | ||
157 | ] | ||
158 | }, | ||
159 | { fields: [ 'duration' ] }, | ||
160 | { fields: [ 'views' ] }, | ||
161 | { fields: [ 'channelId' ] }, | ||
162 | { | ||
163 | fields: [ 'originallyPublishedAt' ], | ||
164 | where: { | ||
165 | originallyPublishedAt: { | ||
166 | [Op.ne]: null | ||
167 | } | ||
168 | } | ||
169 | }, | ||
170 | { | ||
171 | fields: [ 'category' ], // We don't care videos with an unknown category | ||
172 | where: { | ||
173 | category: { | ||
174 | [Op.ne]: null | ||
175 | } | ||
176 | } | ||
177 | }, | ||
178 | { | ||
179 | fields: [ 'licence' ], // We don't care videos with an unknown licence | ||
180 | where: { | ||
181 | licence: { | ||
182 | [Op.ne]: null | ||
183 | } | ||
184 | } | ||
185 | }, | ||
186 | { | ||
187 | fields: [ 'language' ], // We don't care videos with an unknown language | ||
188 | where: { | ||
189 | language: { | ||
190 | [Op.ne]: null | ||
191 | } | ||
192 | } | ||
193 | }, | ||
194 | { | ||
195 | fields: [ 'nsfw' ], // Most of the videos are not NSFW | ||
196 | where: { | ||
197 | nsfw: true | ||
198 | } | ||
199 | }, | ||
200 | { | ||
201 | fields: [ 'remote' ], // Only index local videos | ||
202 | where: { | ||
203 | remote: false | ||
204 | } | ||
205 | }, | ||
206 | { | ||
207 | fields: [ 'uuid' ], | ||
208 | unique: true | ||
209 | }, | ||
210 | { | ||
211 | fields: [ 'url' ], | ||
212 | unique: true | ||
213 | } | ||
214 | ] | ||
215 | |||
216 | export enum ScopeNames { | 136 | export enum ScopeNames { |
217 | AVAILABLE_FOR_LIST_IDS = 'AVAILABLE_FOR_LIST_IDS', | 137 | AVAILABLE_FOR_LIST_IDS = 'AVAILABLE_FOR_LIST_IDS', |
218 | FOR_API = 'FOR_API', | 138 | FOR_API = 'FOR_API', |
@@ -267,7 +187,7 @@ export type AvailableForListIDsOptions = { | |||
267 | } | 187 | } |
268 | 188 | ||
269 | @Scopes(() => ({ | 189 | @Scopes(() => ({ |
270 | [ ScopeNames.FOR_API ]: (options: ForAPIOptions) => { | 190 | [ScopeNames.FOR_API]: (options: ForAPIOptions) => { |
271 | const query: FindOptions = { | 191 | const query: FindOptions = { |
272 | include: [ | 192 | include: [ |
273 | { | 193 | { |
@@ -292,7 +212,7 @@ export type AvailableForListIDsOptions = { | |||
292 | if (options.ids) { | 212 | if (options.ids) { |
293 | query.where = { | 213 | query.where = { |
294 | id: { | 214 | id: { |
295 | [ Op.in ]: options.ids // FIXME: sequelize ANY seems broken | 215 | [Op.in]: options.ids |
296 | } | 216 | } |
297 | } | 217 | } |
298 | } | 218 | } |
@@ -316,7 +236,7 @@ export type AvailableForListIDsOptions = { | |||
316 | 236 | ||
317 | return query | 237 | return query |
318 | }, | 238 | }, |
319 | [ ScopeNames.AVAILABLE_FOR_LIST_IDS ]: (options: AvailableForListIDsOptions) => { | 239 | [ScopeNames.AVAILABLE_FOR_LIST_IDS]: (options: AvailableForListIDsOptions) => { |
320 | const whereAnd = options.baseWhere ? [].concat(options.baseWhere) : [] | 240 | const whereAnd = options.baseWhere ? [].concat(options.baseWhere) : [] |
321 | 241 | ||
322 | const query: FindOptions = { | 242 | const query: FindOptions = { |
@@ -327,11 +247,11 @@ export type AvailableForListIDsOptions = { | |||
327 | const attributesType = options.attributesType || 'id' | 247 | const attributesType = options.attributesType || 'id' |
328 | 248 | ||
329 | if (attributesType === 'id') query.attributes = [ 'id' ] | 249 | if (attributesType === 'id') query.attributes = [ 'id' ] |
330 | else if (attributesType === 'none') query.attributes = [ ] | 250 | else if (attributesType === 'none') query.attributes = [] |
331 | 251 | ||
332 | whereAnd.push({ | 252 | whereAnd.push({ |
333 | id: { | 253 | id: { |
334 | [ Op.notIn ]: Sequelize.literal( | 254 | [Op.notIn]: Sequelize.literal( |
335 | '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")' | 255 | '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")' |
336 | ) | 256 | ) |
337 | } | 257 | } |
@@ -340,7 +260,7 @@ export type AvailableForListIDsOptions = { | |||
340 | if (options.serverAccountId) { | 260 | if (options.serverAccountId) { |
341 | whereAnd.push({ | 261 | whereAnd.push({ |
342 | channelId: { | 262 | channelId: { |
343 | [ Op.notIn ]: Sequelize.literal( | 263 | [Op.notIn]: Sequelize.literal( |
344 | '(' + | 264 | '(' + |
345 | 'SELECT id FROM "videoChannel" WHERE "accountId" IN (' + | 265 | 'SELECT id FROM "videoChannel" WHERE "accountId" IN (' + |
346 | buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) + | 266 | buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) + |
@@ -353,15 +273,14 @@ export type AvailableForListIDsOptions = { | |||
353 | 273 | ||
354 | // Only list public/published videos | 274 | // Only list public/published videos |
355 | if (!options.filter || options.filter !== 'all-local') { | 275 | if (!options.filter || options.filter !== 'all-local') { |
356 | |||
357 | const publishWhere = { | 276 | const publishWhere = { |
358 | // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding | 277 | // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding |
359 | [ Op.or ]: [ | 278 | [Op.or]: [ |
360 | { | 279 | { |
361 | state: VideoState.PUBLISHED | 280 | state: VideoState.PUBLISHED |
362 | }, | 281 | }, |
363 | { | 282 | { |
364 | [ Op.and ]: { | 283 | [Op.and]: { |
365 | state: VideoState.TO_TRANSCODE, | 284 | state: VideoState.TO_TRANSCODE, |
366 | waitTranscoding: false | 285 | waitTranscoding: false |
367 | } | 286 | } |
@@ -448,7 +367,7 @@ export type AvailableForListIDsOptions = { | |||
448 | [Op.or]: [ | 367 | [Op.or]: [ |
449 | { | 368 | { |
450 | id: { | 369 | id: { |
451 | [ Op.in ]: Sequelize.literal( | 370 | [Op.in]: Sequelize.literal( |
452 | '(' + | 371 | '(' + |
453 | 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + | 372 | 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + |
454 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + | 373 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + |
@@ -459,7 +378,7 @@ export type AvailableForListIDsOptions = { | |||
459 | }, | 378 | }, |
460 | { | 379 | { |
461 | id: { | 380 | id: { |
462 | [ Op.in ]: Sequelize.literal( | 381 | [Op.in]: Sequelize.literal( |
463 | '(' + | 382 | '(' + |
464 | 'SELECT "video"."id" AS "id" FROM "video" ' + | 383 | 'SELECT "video"."id" AS "id" FROM "video" ' + |
465 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | 384 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + |
@@ -479,7 +398,7 @@ export type AvailableForListIDsOptions = { | |||
479 | if (options.withFiles === true) { | 398 | if (options.withFiles === true) { |
480 | whereAnd.push({ | 399 | whereAnd.push({ |
481 | id: { | 400 | id: { |
482 | [ Op.in ]: Sequelize.literal( | 401 | [Op.in]: Sequelize.literal( |
483 | '(SELECT "videoId" FROM "videoFile")' | 402 | '(SELECT "videoId" FROM "videoFile")' |
484 | ) | 403 | ) |
485 | } | 404 | } |
@@ -493,7 +412,7 @@ export type AvailableForListIDsOptions = { | |||
493 | 412 | ||
494 | whereAnd.push({ | 413 | whereAnd.push({ |
495 | id: { | 414 | id: { |
496 | [ Op.in ]: Sequelize.literal( | 415 | [Op.in]: Sequelize.literal( |
497 | '(' + | 416 | '(' + |
498 | 'SELECT "videoId" FROM "videoTag" ' + | 417 | 'SELECT "videoId" FROM "videoTag" ' + |
499 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + | 418 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + |
@@ -509,7 +428,7 @@ export type AvailableForListIDsOptions = { | |||
509 | 428 | ||
510 | whereAnd.push({ | 429 | whereAnd.push({ |
511 | id: { | 430 | id: { |
512 | [ Op.in ]: Sequelize.literal( | 431 | [Op.in]: Sequelize.literal( |
513 | '(' + | 432 | '(' + |
514 | 'SELECT "videoId" FROM "videoTag" ' + | 433 | 'SELECT "videoId" FROM "videoTag" ' + |
515 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + | 434 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + |
@@ -529,7 +448,7 @@ export type AvailableForListIDsOptions = { | |||
529 | if (options.categoryOneOf) { | 448 | if (options.categoryOneOf) { |
530 | whereAnd.push({ | 449 | whereAnd.push({ |
531 | category: { | 450 | category: { |
532 | [ Op.or ]: options.categoryOneOf | 451 | [Op.or]: options.categoryOneOf |
533 | } | 452 | } |
534 | }) | 453 | }) |
535 | } | 454 | } |
@@ -537,7 +456,7 @@ export type AvailableForListIDsOptions = { | |||
537 | if (options.licenceOneOf) { | 456 | if (options.licenceOneOf) { |
538 | whereAnd.push({ | 457 | whereAnd.push({ |
539 | licence: { | 458 | licence: { |
540 | [ Op.or ]: options.licenceOneOf | 459 | [Op.or]: options.licenceOneOf |
541 | } | 460 | } |
542 | }) | 461 | }) |
543 | } | 462 | } |
@@ -552,12 +471,12 @@ export type AvailableForListIDsOptions = { | |||
552 | [Op.or]: [ | 471 | [Op.or]: [ |
553 | { | 472 | { |
554 | language: { | 473 | language: { |
555 | [ Op.or ]: videoLanguages | 474 | [Op.or]: videoLanguages |
556 | } | 475 | } |
557 | }, | 476 | }, |
558 | { | 477 | { |
559 | id: { | 478 | id: { |
560 | [ Op.in ]: Sequelize.literal( | 479 | [Op.in]: Sequelize.literal( |
561 | '(' + | 480 | '(' + |
562 | 'SELECT "videoId" FROM "videoCaption" ' + | 481 | 'SELECT "videoId" FROM "videoCaption" ' + |
563 | 'WHERE "language" IN (' + createSafeIn(VideoModel, options.languageOneOf) + ') ' + | 482 | 'WHERE "language" IN (' + createSafeIn(VideoModel, options.languageOneOf) + ') ' + |
@@ -591,12 +510,12 @@ export type AvailableForListIDsOptions = { | |||
591 | } | 510 | } |
592 | 511 | ||
593 | query.where = { | 512 | query.where = { |
594 | [ Op.and ]: whereAnd | 513 | [Op.and]: whereAnd |
595 | } | 514 | } |
596 | 515 | ||
597 | return query | 516 | return query |
598 | }, | 517 | }, |
599 | [ ScopeNames.WITH_THUMBNAILS ]: { | 518 | [ScopeNames.WITH_THUMBNAILS]: { |
600 | include: [ | 519 | include: [ |
601 | { | 520 | { |
602 | model: ThumbnailModel, | 521 | model: ThumbnailModel, |
@@ -604,7 +523,7 @@ export type AvailableForListIDsOptions = { | |||
604 | } | 523 | } |
605 | ] | 524 | ] |
606 | }, | 525 | }, |
607 | [ ScopeNames.WITH_USER_ID ]: { | 526 | [ScopeNames.WITH_USER_ID]: { |
608 | include: [ | 527 | include: [ |
609 | { | 528 | { |
610 | attributes: [ 'accountId' ], | 529 | attributes: [ 'accountId' ], |
@@ -620,7 +539,7 @@ export type AvailableForListIDsOptions = { | |||
620 | } | 539 | } |
621 | ] | 540 | ] |
622 | }, | 541 | }, |
623 | [ ScopeNames.WITH_ACCOUNT_DETAILS ]: { | 542 | [ScopeNames.WITH_ACCOUNT_DETAILS]: { |
624 | include: [ | 543 | include: [ |
625 | { | 544 | { |
626 | model: VideoChannelModel.unscoped(), | 545 | model: VideoChannelModel.unscoped(), |
@@ -672,10 +591,10 @@ export type AvailableForListIDsOptions = { | |||
672 | } | 591 | } |
673 | ] | 592 | ] |
674 | }, | 593 | }, |
675 | [ ScopeNames.WITH_TAGS ]: { | 594 | [ScopeNames.WITH_TAGS]: { |
676 | include: [ TagModel ] | 595 | include: [ TagModel ] |
677 | }, | 596 | }, |
678 | [ ScopeNames.WITH_BLACKLISTED ]: { | 597 | [ScopeNames.WITH_BLACKLISTED]: { |
679 | include: [ | 598 | include: [ |
680 | { | 599 | { |
681 | attributes: [ 'id', 'reason', 'unfederated' ], | 600 | attributes: [ 'id', 'reason', 'unfederated' ], |
@@ -684,7 +603,7 @@ export type AvailableForListIDsOptions = { | |||
684 | } | 603 | } |
685 | ] | 604 | ] |
686 | }, | 605 | }, |
687 | [ ScopeNames.WITH_WEBTORRENT_FILES ]: (withRedundancies = false) => { | 606 | [ScopeNames.WITH_WEBTORRENT_FILES]: (withRedundancies = false) => { |
688 | let subInclude: any[] = [] | 607 | let subInclude: any[] = [] |
689 | 608 | ||
690 | if (withRedundancies === true) { | 609 | if (withRedundancies === true) { |
@@ -708,7 +627,7 @@ export type AvailableForListIDsOptions = { | |||
708 | ] | 627 | ] |
709 | } | 628 | } |
710 | }, | 629 | }, |
711 | [ ScopeNames.WITH_STREAMING_PLAYLISTS ]: (withRedundancies = false) => { | 630 | [ScopeNames.WITH_STREAMING_PLAYLISTS]: (withRedundancies = false) => { |
712 | const subInclude: IncludeOptions[] = [ | 631 | const subInclude: IncludeOptions[] = [ |
713 | { | 632 | { |
714 | model: VideoFileModel.unscoped(), | 633 | model: VideoFileModel.unscoped(), |
@@ -735,7 +654,7 @@ export type AvailableForListIDsOptions = { | |||
735 | ] | 654 | ] |
736 | } | 655 | } |
737 | }, | 656 | }, |
738 | [ ScopeNames.WITH_SCHEDULED_UPDATE ]: { | 657 | [ScopeNames.WITH_SCHEDULED_UPDATE]: { |
739 | include: [ | 658 | include: [ |
740 | { | 659 | { |
741 | model: ScheduleVideoUpdateModel.unscoped(), | 660 | model: ScheduleVideoUpdateModel.unscoped(), |
@@ -743,7 +662,7 @@ export type AvailableForListIDsOptions = { | |||
743 | } | 662 | } |
744 | ] | 663 | ] |
745 | }, | 664 | }, |
746 | [ ScopeNames.WITH_USER_HISTORY ]: (userId: number) => { | 665 | [ScopeNames.WITH_USER_HISTORY]: (userId: number) => { |
747 | return { | 666 | return { |
748 | include: [ | 667 | include: [ |
749 | { | 668 | { |
@@ -760,7 +679,72 @@ export type AvailableForListIDsOptions = { | |||
760 | })) | 679 | })) |
761 | @Table({ | 680 | @Table({ |
762 | tableName: 'video', | 681 | tableName: 'video', |
763 | indexes | 682 | indexes: [ |
683 | buildTrigramSearchIndex('video_name_trigram', 'name'), | ||
684 | |||
685 | { fields: [ 'createdAt' ] }, | ||
686 | { | ||
687 | fields: [ | ||
688 | { name: 'publishedAt', order: 'DESC' }, | ||
689 | { name: 'id', order: 'ASC' } | ||
690 | ] | ||
691 | }, | ||
692 | { fields: [ 'duration' ] }, | ||
693 | { fields: [ 'views' ] }, | ||
694 | { fields: [ 'channelId' ] }, | ||
695 | { | ||
696 | fields: [ 'originallyPublishedAt' ], | ||
697 | where: { | ||
698 | originallyPublishedAt: { | ||
699 | [Op.ne]: null | ||
700 | } | ||
701 | } | ||
702 | }, | ||
703 | { | ||
704 | fields: [ 'category' ], // We don't care videos with an unknown category | ||
705 | where: { | ||
706 | category: { | ||
707 | [Op.ne]: null | ||
708 | } | ||
709 | } | ||
710 | }, | ||
711 | { | ||
712 | fields: [ 'licence' ], // We don't care videos with an unknown licence | ||
713 | where: { | ||
714 | licence: { | ||
715 | [Op.ne]: null | ||
716 | } | ||
717 | } | ||
718 | }, | ||
719 | { | ||
720 | fields: [ 'language' ], // We don't care videos with an unknown language | ||
721 | where: { | ||
722 | language: { | ||
723 | [Op.ne]: null | ||
724 | } | ||
725 | } | ||
726 | }, | ||
727 | { | ||
728 | fields: [ 'nsfw' ], // Most of the videos are not NSFW | ||
729 | where: { | ||
730 | nsfw: true | ||
731 | } | ||
732 | }, | ||
733 | { | ||
734 | fields: [ 'remote' ], // Only index local videos | ||
735 | where: { | ||
736 | remote: false | ||
737 | } | ||
738 | }, | ||
739 | { | ||
740 | fields: [ 'uuid' ], | ||
741 | unique: true | ||
742 | }, | ||
743 | { | ||
744 | fields: [ 'url' ], | ||
745 | unique: true | ||
746 | } | ||
747 | ] | ||
764 | }) | 748 | }) |
765 | export class VideoModel extends Model<VideoModel> { | 749 | export class VideoModel extends Model<VideoModel> { |
766 | 750 | ||
@@ -1031,7 +1015,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1031 | }, | 1015 | }, |
1032 | onDelete: 'cascade', | 1016 | onDelete: 'cascade', |
1033 | hooks: true, | 1017 | hooks: true, |
1034 | [ 'separate' as any ]: true | 1018 | ['separate' as any]: true |
1035 | }) | 1019 | }) |
1036 | VideoCaptions: VideoCaptionModel[] | 1020 | VideoCaptions: VideoCaptionModel[] |
1037 | 1021 | ||
@@ -1127,16 +1111,16 @@ export class VideoModel extends Model<VideoModel> { | |||
1127 | order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ] as any), // FIXME: sequelize typings | 1111 | order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ] as any), // FIXME: sequelize typings |
1128 | where: { | 1112 | where: { |
1129 | id: { | 1113 | id: { |
1130 | [ Op.in ]: Sequelize.literal('(' + rawQuery + ')') | 1114 | [Op.in]: Sequelize.literal('(' + rawQuery + ')') |
1131 | }, | 1115 | }, |
1132 | [ Op.or ]: [ | 1116 | [Op.or]: [ |
1133 | { privacy: VideoPrivacy.PUBLIC }, | 1117 | { privacy: VideoPrivacy.PUBLIC }, |
1134 | { privacy: VideoPrivacy.UNLISTED } | 1118 | { privacy: VideoPrivacy.UNLISTED } |
1135 | ] | 1119 | ] |
1136 | }, | 1120 | }, |
1137 | include: [ | 1121 | include: [ |
1138 | { | 1122 | { |
1139 | attributes: [ 'language' ], | 1123 | attributes: [ 'language', 'fileUrl' ], |
1140 | model: VideoCaptionModel.unscoped(), | 1124 | model: VideoCaptionModel.unscoped(), |
1141 | required: false | 1125 | required: false |
1142 | }, | 1126 | }, |
@@ -1146,10 +1130,10 @@ export class VideoModel extends Model<VideoModel> { | |||
1146 | required: false, | 1130 | required: false, |
1147 | // We only want videos shared by this actor | 1131 | // We only want videos shared by this actor |
1148 | where: { | 1132 | where: { |
1149 | [ Op.and ]: [ | 1133 | [Op.and]: [ |
1150 | { | 1134 | { |
1151 | id: { | 1135 | id: { |
1152 | [ Op.not ]: null | 1136 | [Op.not]: null |
1153 | } | 1137 | } |
1154 | }, | 1138 | }, |
1155 | { | 1139 | { |
@@ -1199,8 +1183,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1199 | // totals: totalVideos + totalVideoShares | 1183 | // totals: totalVideos + totalVideoShares |
1200 | let totalVideos = 0 | 1184 | let totalVideos = 0 |
1201 | let totalVideoShares = 0 | 1185 | let totalVideoShares = 0 |
1202 | if (totals[ 0 ]) totalVideos = parseInt(totals[ 0 ].total, 10) | 1186 | if (totals[0]) totalVideos = parseInt(totals[0].total, 10) |
1203 | if (totals[ 1 ]) totalVideoShares = parseInt(totals[ 1 ].total, 10) | 1187 | if (totals[1]) totalVideoShares = parseInt(totals[1].total, 10) |
1204 | 1188 | ||
1205 | const total = totalVideos + totalVideoShares | 1189 | const total = totalVideos + totalVideoShares |
1206 | return { | 1190 | return { |
@@ -1243,7 +1227,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1243 | baseQuery = Object.assign(baseQuery, { | 1227 | baseQuery = Object.assign(baseQuery, { |
1244 | where: { | 1228 | where: { |
1245 | name: { | 1229 | name: { |
1246 | [ Op.iLike ]: '%' + search + '%' | 1230 | [Op.iLike]: '%' + search + '%' |
1247 | } | 1231 | } |
1248 | } | 1232 | } |
1249 | }) | 1233 | }) |
@@ -1273,25 +1257,25 @@ export class VideoModel extends Model<VideoModel> { | |||
1273 | } | 1257 | } |
1274 | 1258 | ||
1275 | static async listForApi (options: { | 1259 | static async listForApi (options: { |
1276 | start: number, | 1260 | start: number |
1277 | count: number, | 1261 | count: number |
1278 | sort: string, | 1262 | sort: string |
1279 | nsfw: boolean, | 1263 | nsfw: boolean |
1280 | includeLocalVideos: boolean, | 1264 | includeLocalVideos: boolean |
1281 | withFiles: boolean, | 1265 | withFiles: boolean |
1282 | categoryOneOf?: number[], | 1266 | categoryOneOf?: number[] |
1283 | licenceOneOf?: number[], | 1267 | licenceOneOf?: number[] |
1284 | languageOneOf?: string[], | 1268 | languageOneOf?: string[] |
1285 | tagsOneOf?: string[], | 1269 | tagsOneOf?: string[] |
1286 | tagsAllOf?: string[], | 1270 | tagsAllOf?: string[] |
1287 | filter?: VideoFilter, | 1271 | filter?: VideoFilter |
1288 | accountId?: number, | 1272 | accountId?: number |
1289 | videoChannelId?: number, | 1273 | videoChannelId?: number |
1290 | followerActorId?: number | 1274 | followerActorId?: number |
1291 | videoPlaylistId?: number, | 1275 | videoPlaylistId?: number |
1292 | trendingDays?: number, | 1276 | trendingDays?: number |
1293 | user?: MUserAccountId, | 1277 | user?: MUserAccountId |
1294 | historyOfUser?: MUserId, | 1278 | historyOfUser?: MUserId |
1295 | countVideos?: boolean | 1279 | countVideos?: boolean |
1296 | }) { | 1280 | }) { |
1297 | if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) { | 1281 | if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) { |
@@ -1357,7 +1341,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1357 | tagsAllOf?: string[] | 1341 | tagsAllOf?: string[] |
1358 | durationMin?: number // seconds | 1342 | durationMin?: number // seconds |
1359 | durationMax?: number // seconds | 1343 | durationMax?: number // seconds |
1360 | user?: MUserAccountId, | 1344 | user?: MUserAccountId |
1361 | filter?: VideoFilter | 1345 | filter?: VideoFilter |
1362 | }) { | 1346 | }) { |
1363 | const whereAnd = [] | 1347 | const whereAnd = [] |
@@ -1365,8 +1349,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1365 | if (options.startDate || options.endDate) { | 1349 | if (options.startDate || options.endDate) { |
1366 | const publishedAtRange = {} | 1350 | const publishedAtRange = {} |
1367 | 1351 | ||
1368 | if (options.startDate) publishedAtRange[ Op.gte ] = options.startDate | 1352 | if (options.startDate) publishedAtRange[Op.gte] = options.startDate |
1369 | if (options.endDate) publishedAtRange[ Op.lte ] = options.endDate | 1353 | if (options.endDate) publishedAtRange[Op.lte] = options.endDate |
1370 | 1354 | ||
1371 | whereAnd.push({ publishedAt: publishedAtRange }) | 1355 | whereAnd.push({ publishedAt: publishedAtRange }) |
1372 | } | 1356 | } |
@@ -1374,8 +1358,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1374 | if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) { | 1358 | if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) { |
1375 | const originallyPublishedAtRange = {} | 1359 | const originallyPublishedAtRange = {} |
1376 | 1360 | ||
1377 | if (options.originallyPublishedStartDate) originallyPublishedAtRange[ Op.gte ] = options.originallyPublishedStartDate | 1361 | if (options.originallyPublishedStartDate) originallyPublishedAtRange[Op.gte] = options.originallyPublishedStartDate |
1378 | if (options.originallyPublishedEndDate) originallyPublishedAtRange[ Op.lte ] = options.originallyPublishedEndDate | 1362 | if (options.originallyPublishedEndDate) originallyPublishedAtRange[Op.lte] = options.originallyPublishedEndDate |
1379 | 1363 | ||
1380 | whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange }) | 1364 | whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange }) |
1381 | } | 1365 | } |
@@ -1383,8 +1367,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1383 | if (options.durationMin || options.durationMax) { | 1367 | if (options.durationMin || options.durationMax) { |
1384 | const durationRange = {} | 1368 | const durationRange = {} |
1385 | 1369 | ||
1386 | if (options.durationMin) durationRange[ Op.gte ] = options.durationMin | 1370 | if (options.durationMin) durationRange[Op.gte] = options.durationMin |
1387 | if (options.durationMax) durationRange[ Op.lte ] = options.durationMax | 1371 | if (options.durationMax) durationRange[Op.lte] = options.durationMax |
1388 | 1372 | ||
1389 | whereAnd.push({ duration: durationRange }) | 1373 | whereAnd.push({ duration: durationRange }) |
1390 | } | 1374 | } |
@@ -1395,7 +1379,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1395 | if (options.search) { | 1379 | if (options.search) { |
1396 | const trigramSearch = { | 1380 | const trigramSearch = { |
1397 | id: { | 1381 | id: { |
1398 | [ Op.in ]: Sequelize.literal( | 1382 | [Op.in]: Sequelize.literal( |
1399 | '(' + | 1383 | '(' + |
1400 | 'SELECT "video"."id" FROM "video" ' + | 1384 | 'SELECT "video"."id" FROM "video" ' + |
1401 | 'WHERE ' + | 1385 | 'WHERE ' + |
@@ -1593,8 +1577,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1593 | } | 1577 | } |
1594 | 1578 | ||
1595 | static loadForGetAPI (parameters: { | 1579 | static loadForGetAPI (parameters: { |
1596 | id: number | string, | 1580 | id: number | string |
1597 | t?: Transaction, | 1581 | t?: Transaction |
1598 | userId?: number | 1582 | userId?: number |
1599 | }): Bluebird<MVideoDetails> { | 1583 | }): Bluebird<MVideoDetails> { |
1600 | const { id, t, userId } = parameters | 1584 | const { id, t, userId } = parameters |
@@ -1660,9 +1644,9 @@ export class VideoModel extends Model<VideoModel> { | |||
1660 | static checkVideoHasInstanceFollow (videoId: number, followerActorId: number) { | 1644 | static checkVideoHasInstanceFollow (videoId: number, followerActorId: number) { |
1661 | // Instances only share videos | 1645 | // Instances only share videos |
1662 | const query = 'SELECT 1 FROM "videoShare" ' + | 1646 | const query = 'SELECT 1 FROM "videoShare" ' + |
1663 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + | 1647 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + |
1664 | 'WHERE "actorFollow"."actorId" = $followerActorId AND "videoShare"."videoId" = $videoId ' + | 1648 | 'WHERE "actorFollow"."actorId" = $followerActorId AND "videoShare"."videoId" = $videoId ' + |
1665 | 'LIMIT 1' | 1649 | 'LIMIT 1' |
1666 | 1650 | ||
1667 | const options = { | 1651 | const options = { |
1668 | type: QueryTypes.SELECT as QueryTypes.SELECT, | 1652 | type: QueryTypes.SELECT as QueryTypes.SELECT, |
@@ -1694,7 +1678,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1694 | } | 1678 | } |
1695 | 1679 | ||
1696 | return VideoModel.findAll(query) | 1680 | return VideoModel.findAll(query) |
1697 | .then(videos => videos.map(v => v.id)) | 1681 | .then(videos => videos.map(v => v.id)) |
1698 | } | 1682 | } |
1699 | 1683 | ||
1700 | // threshold corresponds to how many video the field should have to be returned | 1684 | // threshold corresponds to how many video the field should have to be returned |
@@ -1714,14 +1698,14 @@ export class VideoModel extends Model<VideoModel> { | |||
1714 | limit: count, | 1698 | limit: count, |
1715 | group: field, | 1699 | group: field, |
1716 | having: Sequelize.where( | 1700 | having: Sequelize.where( |
1717 | Sequelize.fn('COUNT', Sequelize.col(field)), { [ Op.gte ]: threshold } | 1701 | Sequelize.fn('COUNT', Sequelize.col(field)), { [Op.gte]: threshold } |
1718 | ), | 1702 | ), |
1719 | order: [ (this.sequelize as any).random() ] | 1703 | order: [ (this.sequelize as any).random() ] |
1720 | } | 1704 | } |
1721 | 1705 | ||
1722 | return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] }) | 1706 | return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] }) |
1723 | .findAll(query) | 1707 | .findAll(query) |
1724 | .then(rows => rows.map(r => r[ field ])) | 1708 | .then(rows => rows.map(r => r[field])) |
1725 | } | 1709 | } |
1726 | 1710 | ||
1727 | static buildTrendingQuery (trendingDays: number) { | 1711 | static buildTrendingQuery (trendingDays: number) { |
@@ -1732,7 +1716,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1732 | required: false, | 1716 | required: false, |
1733 | where: { | 1717 | where: { |
1734 | startDate: { | 1718 | startDate: { |
1735 | [ Op.gte ]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays) | 1719 | [Op.gte]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays) |
1736 | } | 1720 | } |
1737 | } | 1721 | } |
1738 | } | 1722 | } |
@@ -1815,23 +1799,23 @@ export class VideoModel extends Model<VideoModel> { | |||
1815 | } | 1799 | } |
1816 | 1800 | ||
1817 | static getCategoryLabel (id: number) { | 1801 | static getCategoryLabel (id: number) { |
1818 | return VIDEO_CATEGORIES[ id ] || 'Misc' | 1802 | return VIDEO_CATEGORIES[id] || 'Misc' |
1819 | } | 1803 | } |
1820 | 1804 | ||
1821 | static getLicenceLabel (id: number) { | 1805 | static getLicenceLabel (id: number) { |
1822 | return VIDEO_LICENCES[ id ] || 'Unknown' | 1806 | return VIDEO_LICENCES[id] || 'Unknown' |
1823 | } | 1807 | } |
1824 | 1808 | ||
1825 | static getLanguageLabel (id: string) { | 1809 | static getLanguageLabel (id: string) { |
1826 | return VIDEO_LANGUAGES[ id ] || 'Unknown' | 1810 | return VIDEO_LANGUAGES[id] || 'Unknown' |
1827 | } | 1811 | } |
1828 | 1812 | ||
1829 | static getPrivacyLabel (id: number) { | 1813 | static getPrivacyLabel (id: number) { |
1830 | return VIDEO_PRIVACIES[ id ] || 'Unknown' | 1814 | return VIDEO_PRIVACIES[id] || 'Unknown' |
1831 | } | 1815 | } |
1832 | 1816 | ||
1833 | static getStateLabel (id: number) { | 1817 | static getStateLabel (id: number) { |
1834 | return VIDEO_STATES[ id ] || 'Unknown' | 1818 | return VIDEO_STATES[id] || 'Unknown' |
1835 | } | 1819 | } |
1836 | 1820 | ||
1837 | isBlacklisted () { | 1821 | isBlacklisted () { |
@@ -1843,7 +1827,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1843 | this.VideoChannel.Account.isBlocked() | 1827 | this.VideoChannel.Account.isBlocked() |
1844 | } | 1828 | } |
1845 | 1829 | ||
1846 | getQualityFileBy <T extends MVideoWithFile> (this: T, fun: (files: MVideoFile[], it: (file: MVideoFile) => number) => MVideoFile) { | 1830 | getQualityFileBy<T extends MVideoWithFile> (this: T, fun: (files: MVideoFile[], it: (file: MVideoFile) => number) => MVideoFile) { |
1847 | if (Array.isArray(this.VideoFiles) && this.VideoFiles.length !== 0) { | 1831 | if (Array.isArray(this.VideoFiles) && this.VideoFiles.length !== 0) { |
1848 | const file = fun(this.VideoFiles, file => file.resolution) | 1832 | const file = fun(this.VideoFiles, file => file.resolution) |
1849 | 1833 | ||
@@ -1861,15 +1845,15 @@ export class VideoModel extends Model<VideoModel> { | |||
1861 | return undefined | 1845 | return undefined |
1862 | } | 1846 | } |
1863 | 1847 | ||
1864 | getMaxQualityFile <T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo { | 1848 | getMaxQualityFile<T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo { |
1865 | return this.getQualityFileBy(maxBy) | 1849 | return this.getQualityFileBy(maxBy) |
1866 | } | 1850 | } |
1867 | 1851 | ||
1868 | getMinQualityFile <T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo { | 1852 | getMinQualityFile<T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo { |
1869 | return this.getQualityFileBy(minBy) | 1853 | return this.getQualityFileBy(minBy) |
1870 | } | 1854 | } |
1871 | 1855 | ||
1872 | getWebTorrentFile <T extends MVideoWithFile> (this: T, resolution: number): MVideoFileVideo { | 1856 | getWebTorrentFile<T extends MVideoWithFile> (this: T, resolution: number): MVideoFileVideo { |
1873 | if (Array.isArray(this.VideoFiles) === false) return undefined | 1857 | if (Array.isArray(this.VideoFiles) === false) return undefined |
1874 | 1858 | ||
1875 | const file = this.VideoFiles.find(f => f.resolution === resolution) | 1859 | const file = this.VideoFiles.find(f => f.resolution === resolution) |
@@ -1992,8 +1976,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1992 | } | 1976 | } |
1993 | 1977 | ||
1994 | this.VideoStreamingPlaylists = this.VideoStreamingPlaylists | 1978 | this.VideoStreamingPlaylists = this.VideoStreamingPlaylists |
1995 | .filter(s => s.type !== VideoStreamingPlaylistType.HLS) | 1979 | .filter(s => s.type !== VideoStreamingPlaylistType.HLS) |
1996 | .concat(toAdd) | 1980 | .concat(toAdd) |
1997 | } | 1981 | } |
1998 | 1982 | ||
1999 | removeFile (videoFile: MVideoFile, isRedundancy = false) { | 1983 | removeFile (videoFile: MVideoFile, isRedundancy = false) { |
@@ -2014,7 +1998,7 @@ export class VideoModel extends Model<VideoModel> { | |||
2014 | await remove(directoryPath) | 1998 | await remove(directoryPath) |
2015 | 1999 | ||
2016 | if (isRedundancy !== true) { | 2000 | if (isRedundancy !== true) { |
2017 | let streamingPlaylistWithFiles = streamingPlaylist as MStreamingPlaylistFilesVideo | 2001 | const streamingPlaylistWithFiles = streamingPlaylist as MStreamingPlaylistFilesVideo |
2018 | streamingPlaylistWithFiles.Video = this | 2002 | streamingPlaylistWithFiles.Video = this |
2019 | 2003 | ||
2020 | if (!Array.isArray(streamingPlaylistWithFiles.VideoFiles)) { | 2004 | if (!Array.isArray(streamingPlaylistWithFiles.VideoFiles)) { |
diff --git a/server/tests/api/activitypub/client.ts b/server/tests/api/activitypub/client.ts index 34c6be49b..d16f05108 100644 --- a/server/tests/api/activitypub/client.ts +++ b/server/tests/api/activitypub/client.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -6,8 +6,6 @@ import { | |||
6 | cleanupTests, | 6 | cleanupTests, |
7 | doubleFollow, | 7 | doubleFollow, |
8 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
9 | flushTests, | ||
10 | killallServers, | ||
11 | makeActivityPubGetRequest, | 9 | makeActivityPubGetRequest, |
12 | ServerInfo, | 10 | ServerInfo, |
13 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
diff --git a/server/tests/api/activitypub/fetch.ts b/server/tests/api/activitypub/fetch.ts index 3d54c2042..35fd94eed 100644 --- a/server/tests/api/activitypub/fetch.ts +++ b/server/tests/api/activitypub/fetch.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
@@ -8,9 +8,7 @@ import { | |||
8 | createUser, | 8 | createUser, |
9 | doubleFollow, | 9 | doubleFollow, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
11 | flushTests, | ||
12 | getVideosListSort, | 11 | getVideosListSort, |
13 | killallServers, | ||
14 | ServerInfo, | 12 | ServerInfo, |
15 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
16 | setActorField, | 14 | setActorField, |
diff --git a/server/tests/api/activitypub/helpers.ts b/server/tests/api/activitypub/helpers.ts index 8c00ba3d6..60d95b823 100644 --- a/server/tests/api/activitypub/helpers.ts +++ b/server/tests/api/activitypub/helpers.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
diff --git a/server/tests/api/activitypub/refresher.ts b/server/tests/api/activitypub/refresher.ts index aa4bc6c0f..232c5d823 100644 --- a/server/tests/api/activitypub/refresher.ts +++ b/server/tests/api/activitypub/refresher.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
@@ -43,32 +43,32 @@ describe('Test AP refresher', function () { | |||
43 | await setDefaultVideoChannel(servers) | 43 | await setDefaultVideoChannel(servers) |
44 | 44 | ||
45 | { | 45 | { |
46 | videoUUID1 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video1' })).uuid | 46 | videoUUID1 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video1' })).uuid |
47 | videoUUID2 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video2' })).uuid | 47 | videoUUID2 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video2' })).uuid |
48 | videoUUID3 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video3' })).uuid | 48 | videoUUID3 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video3' })).uuid |
49 | } | 49 | } |
50 | 50 | ||
51 | { | 51 | { |
52 | const a1 = await generateUserAccessToken(servers[ 1 ], 'user1') | 52 | const a1 = await generateUserAccessToken(servers[1], 'user1') |
53 | await uploadVideo(servers[ 1 ].url, a1, { name: 'video4' }) | 53 | await uploadVideo(servers[1].url, a1, { name: 'video4' }) |
54 | 54 | ||
55 | const a2 = await generateUserAccessToken(servers[ 1 ], 'user2') | 55 | const a2 = await generateUserAccessToken(servers[1], 'user2') |
56 | await uploadVideo(servers[ 1 ].url, a2, { name: 'video5' }) | 56 | await uploadVideo(servers[1].url, a2, { name: 'video5' }) |
57 | } | 57 | } |
58 | 58 | ||
59 | { | 59 | { |
60 | 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 } |
61 | 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 }) |
62 | playlistUUID1 = res.body.videoPlaylist.uuid | 62 | playlistUUID1 = res.body.videoPlaylist.uuid |
63 | } | 63 | } |
64 | 64 | ||
65 | { | 65 | { |
66 | 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 } |
67 | 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 }) |
68 | playlistUUID2 = res.body.videoPlaylist.uuid | 68 | playlistUUID2 = res.body.videoPlaylist.uuid |
69 | } | 69 | } |
70 | 70 | ||
71 | await doubleFollow(servers[ 0 ], servers[ 1 ]) | 71 | await doubleFollow(servers[0], servers[1]) |
72 | }) | 72 | }) |
73 | 73 | ||
74 | describe('Videos refresher', function () { | 74 | describe('Videos refresher', function () { |
@@ -79,34 +79,34 @@ describe('Test AP refresher', function () { | |||
79 | await wait(10000) | 79 | await wait(10000) |
80 | 80 | ||
81 | // Change UUID so the remote server returns a 404 | 81 | // Change UUID so the remote server returns a 404 |
82 | await setVideoField(servers[ 1 ].internalServerNumber, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f') | 82 | await setVideoField(servers[1].internalServerNumber, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f') |
83 | 83 | ||
84 | await getVideo(servers[ 0 ].url, videoUUID1) | 84 | await getVideo(servers[0].url, videoUUID1) |
85 | await getVideo(servers[ 0 ].url, videoUUID2) | 85 | await getVideo(servers[0].url, videoUUID2) |
86 | 86 | ||
87 | await waitJobs(servers) | 87 | await waitJobs(servers) |
88 | 88 | ||
89 | await getVideo(servers[ 0 ].url, videoUUID1, 404) | 89 | await getVideo(servers[0].url, videoUUID1, 404) |
90 | await getVideo(servers[ 0 ].url, videoUUID2, 200) | 90 | await getVideo(servers[0].url, videoUUID2, 200) |
91 | }) | 91 | }) |
92 | 92 | ||
93 | it('Should not update a remote video if the remote instance is down', async function () { | 93 | it('Should not update a remote video if the remote instance is down', async function () { |
94 | this.timeout(70000) | 94 | this.timeout(70000) |
95 | 95 | ||
96 | killallServers([ servers[ 1 ] ]) | 96 | killallServers([ servers[1] ]) |
97 | 97 | ||
98 | await setVideoField(servers[ 1 ].internalServerNumber, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e') | 98 | await setVideoField(servers[1].internalServerNumber, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e') |
99 | 99 | ||
100 | // Video will need a refresh | 100 | // Video will need a refresh |
101 | await wait(10000) | 101 | await wait(10000) |
102 | 102 | ||
103 | await getVideo(servers[ 0 ].url, videoUUID3) | 103 | await getVideo(servers[0].url, videoUUID3) |
104 | // The refresh should fail | 104 | // The refresh should fail |
105 | await waitJobs([ servers[ 0 ] ]) | 105 | await waitJobs([ servers[0] ]) |
106 | 106 | ||
107 | await reRunServer(servers[ 1 ]) | 107 | await reRunServer(servers[1]) |
108 | 108 | ||
109 | await getVideo(servers[ 0 ].url, videoUUID3, 200) | 109 | await getVideo(servers[0].url, videoUUID3, 200) |
110 | }) | 110 | }) |
111 | }) | 111 | }) |
112 | 112 | ||
@@ -118,16 +118,16 @@ describe('Test AP refresher', function () { | |||
118 | await wait(10000) | 118 | await wait(10000) |
119 | 119 | ||
120 | // Change actor name so the remote server returns a 404 | 120 | // Change actor name so the remote server returns a 404 |
121 | const to = 'http://localhost:' + servers[ 1 ].port + '/accounts/user2' | 121 | const to = 'http://localhost:' + servers[1].port + '/accounts/user2' |
122 | await setActorField(servers[ 1 ].internalServerNumber, to, 'preferredUsername', 'toto') | 122 | await setActorField(servers[1].internalServerNumber, to, 'preferredUsername', 'toto') |
123 | 123 | ||
124 | await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port) | 124 | await getAccount(servers[0].url, 'user1@localhost:' + servers[1].port) |
125 | await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port) | 125 | await getAccount(servers[0].url, 'user2@localhost:' + servers[1].port) |
126 | 126 | ||
127 | await waitJobs(servers) | 127 | await waitJobs(servers) |
128 | 128 | ||
129 | await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port, 200) | 129 | await getAccount(servers[0].url, 'user1@localhost:' + servers[1].port, 200) |
130 | await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port, 404) | 130 | await getAccount(servers[0].url, 'user2@localhost:' + servers[1].port, 404) |
131 | }) | 131 | }) |
132 | }) | 132 | }) |
133 | 133 | ||
@@ -139,15 +139,15 @@ describe('Test AP refresher', function () { | |||
139 | await wait(10000) | 139 | await wait(10000) |
140 | 140 | ||
141 | // Change UUID so the remote server returns a 404 | 141 | // Change UUID so the remote server returns a 404 |
142 | await setPlaylistField(servers[ 1 ].internalServerNumber, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e') | 142 | await setPlaylistField(servers[1].internalServerNumber, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e') |
143 | 143 | ||
144 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID1) | 144 | await getVideoPlaylist(servers[0].url, playlistUUID1) |
145 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID2) | 145 | await getVideoPlaylist(servers[0].url, playlistUUID2) |
146 | 146 | ||
147 | await waitJobs(servers) | 147 | await waitJobs(servers) |
148 | 148 | ||
149 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID1, 200) | 149 | await getVideoPlaylist(servers[0].url, playlistUUID1, 200) |
150 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID2, 404) | 150 | await getVideoPlaylist(servers[0].url, playlistUUID2, 404) |
151 | }) | 151 | }) |
152 | }) | 152 | }) |
153 | 153 | ||
diff --git a/server/tests/api/activitypub/security.ts b/server/tests/api/activitypub/security.ts index dc960c5c3..7e58bf065 100644 --- a/server/tests/api/activitypub/security.ts +++ b/server/tests/api/activitypub/security.ts | |||
@@ -1,15 +1,8 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { cleanupTests, closeAllSequelize, flushAndRunMultipleServers, ServerInfo, setActorField } from '../../../../shared/extra-utils' |
6 | cleanupTests, | ||
7 | closeAllSequelize, | ||
8 | flushAndRunMultipleServers, | ||
9 | killallServers, | ||
10 | ServerInfo, | ||
11 | setActorField | ||
12 | } from '../../../../shared/extra-utils' | ||
13 | import { HTTP_SIGNATURE } from '../../../initializers/constants' | 6 | import { HTTP_SIGNATURE } from '../../../initializers/constants' |
14 | import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils' | 7 | import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils' |
15 | import * as chai from 'chai' | 8 | import * as chai from 'chai' |
@@ -33,7 +26,7 @@ function getAnnounceWithoutContext (server2: ServerInfo) { | |||
33 | if (Array.isArray(json[key])) { | 26 | if (Array.isArray(json[key])) { |
34 | result[key] = json[key].map(v => v.replace(':9002', `:${server2.port}`)) | 27 | result[key] = json[key].map(v => v.replace(':9002', `:${server2.port}`)) |
35 | } else { | 28 | } else { |
36 | result[ key ] = json[ key ].replace(':9002', `:${server2.port}`) | 29 | result[key] = json[key].replace(':9002', `:${server2.port}`) |
37 | } | 30 | } |
38 | } | 31 | } |
39 | 32 | ||
diff --git a/server/tests/api/check-params/accounts.ts b/server/tests/api/check-params/accounts.ts index 4f79685bd..c29af7cd7 100644 --- a/server/tests/api/check-params/accounts.ts +++ b/server/tests/api/check-params/accounts.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/blocklist.ts b/server/tests/api/check-params/blocklist.ts index 0661676ce..fb459f756 100644 --- a/server/tests/api/check-params/blocklist.ts +++ b/server/tests/api/check-params/blocklist.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts index 443fbcb60..f1a79806b 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { omit } from 'lodash' | 3 | import { omit } from 'lodash' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/check-params/contact-form.ts b/server/tests/api/check-params/contact-form.ts index b3051945e..b2126b9b0 100644 --- a/server/tests/api/check-params/contact-form.ts +++ b/server/tests/api/check-params/contact-form.ts | |||
@@ -1,22 +1,8 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { cleanupTests, flushAndRunServer, immutableAssign, killallServers, reRunServer, ServerInfo } from '../../../../shared/extra-utils' |
6 | flushTests, | ||
7 | immutableAssign, | ||
8 | killallServers, | ||
9 | reRunServer, | ||
10 | flushAndRunServer, | ||
11 | ServerInfo, | ||
12 | setAccessTokensToServers, cleanupTests | ||
13 | } from '../../../../shared/extra-utils' | ||
14 | import { | ||
15 | checkBadCountPagination, | ||
16 | checkBadSortPagination, | ||
17 | checkBadStartPagination | ||
18 | } from '../../../../shared/extra-utils/requests/check-api-params' | ||
19 | import { getAccount } from '../../../../shared/extra-utils/users/accounts' | ||
20 | import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' | 6 | import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' |
21 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' | 7 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' |
22 | 8 | ||
diff --git a/server/tests/api/check-params/debug.ts b/server/tests/api/check-params/debug.ts index 8dad26723..5fac73485 100644 --- a/server/tests/api/check-params/debug.ts +++ b/server/tests/api/check-params/debug.ts | |||
@@ -1,15 +1,14 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
6 | cleanupTests, | ||
6 | createUser, | 7 | createUser, |
7 | flushTests, | ||
8 | killallServers, | ||
9 | flushAndRunServer, | 8 | flushAndRunServer, |
10 | ServerInfo, | 9 | ServerInfo, |
11 | setAccessTokensToServers, | 10 | setAccessTokensToServers, |
12 | userLogin, cleanupTests | 11 | userLogin |
13 | } from '../../../../shared/extra-utils' | 12 | } from '../../../../shared/extra-utils' |
14 | import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests' | 13 | import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests' |
15 | 14 | ||
diff --git a/server/tests/api/check-params/follows.ts b/server/tests/api/check-params/follows.ts index be2a603a3..2c2224a45 100644 --- a/server/tests/api/check-params/follows.ts +++ b/server/tests/api/check-params/follows.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/jobs.ts b/server/tests/api/check-params/jobs.ts index 22e237964..8f4af8d16 100644 --- a/server/tests/api/check-params/jobs.ts +++ b/server/tests/api/check-params/jobs.ts | |||
@@ -1,16 +1,14 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
6 | cleanupTests, | ||
6 | createUser, | 7 | createUser, |
7 | flushTests, | ||
8 | killallServers, | ||
9 | flushAndRunServer, | 8 | flushAndRunServer, |
10 | ServerInfo, | 9 | ServerInfo, |
11 | setAccessTokensToServers, | 10 | setAccessTokensToServers, |
12 | userLogin, | 11 | userLogin |
13 | cleanupTests | ||
14 | } from '../../../../shared/extra-utils' | 12 | } from '../../../../shared/extra-utils' |
15 | import { | 13 | import { |
16 | checkBadCountPagination, | 14 | checkBadCountPagination, |
diff --git a/server/tests/api/check-params/logs.ts b/server/tests/api/check-params/logs.ts index f9d96bcc0..719da54e6 100644 --- a/server/tests/api/check-params/logs.ts +++ b/server/tests/api/check-params/logs.ts | |||
@@ -1,16 +1,14 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
6 | cleanupTests, | ||
6 | createUser, | 7 | createUser, |
7 | flushTests, | ||
8 | killallServers, | ||
9 | flushAndRunServer, | 8 | flushAndRunServer, |
10 | ServerInfo, | 9 | ServerInfo, |
11 | setAccessTokensToServers, | 10 | setAccessTokensToServers, |
12 | userLogin, | 11 | userLogin |
13 | cleanupTests | ||
14 | } from '../../../../shared/extra-utils' | 12 | } from '../../../../shared/extra-utils' |
15 | import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests' | 13 | import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests' |
16 | 14 | ||
diff --git a/server/tests/api/check-params/plugins.ts b/server/tests/api/check-params/plugins.ts index 9553bce17..cf80b35c2 100644 --- a/server/tests/api/check-params/plugins.ts +++ b/server/tests/api/check-params/plugins.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/redundancy.ts b/server/tests/api/check-params/redundancy.ts index 6471da840..b2370a094 100644 --- a/server/tests/api/check-params/redundancy.ts +++ b/server/tests/api/check-params/redundancy.ts | |||
@@ -1,23 +1,27 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
6 | checkBadCountPagination, | ||
7 | checkBadSortPagination, | ||
8 | checkBadStartPagination, | ||
6 | cleanupTests, | 9 | cleanupTests, |
7 | createUser, | 10 | createUser, |
8 | doubleFollow, | 11 | doubleFollow, |
9 | flushAndRunMultipleServers, | 12 | flushAndRunMultipleServers, makeDeleteRequest, |
10 | flushTests, | 13 | makeGetRequest, makePostBodyRequest, |
11 | killallServers, | ||
12 | makePutBodyRequest, | 14 | makePutBodyRequest, |
13 | ServerInfo, | 15 | ServerInfo, |
14 | setAccessTokensToServers, | 16 | setAccessTokensToServers, uploadVideoAndGetId, |
15 | userLogin | 17 | userLogin, waitJobs |
16 | } from '../../../../shared/extra-utils' | 18 | } from '../../../../shared/extra-utils' |
17 | 19 | ||
18 | describe('Test server redundancy API validators', function () { | 20 | describe('Test server redundancy API validators', function () { |
19 | let servers: ServerInfo[] | 21 | let servers: ServerInfo[] |
20 | let userAccessToken = null | 22 | let userAccessToken = null |
23 | let videoIdLocal: number | ||
24 | let videoIdRemote: number | ||
21 | 25 | ||
22 | // --------------------------------------------------------------- | 26 | // --------------------------------------------------------------- |
23 | 27 | ||
@@ -34,11 +38,136 @@ describe('Test server redundancy API validators', function () { | |||
34 | password: 'password' | 38 | password: 'password' |
35 | } | 39 | } |
36 | 40 | ||
37 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 41 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
38 | userAccessToken = await userLogin(servers[0], user) | 42 | userAccessToken = await userLogin(servers[0], user) |
43 | |||
44 | videoIdLocal = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video' })).id | ||
45 | videoIdRemote = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video' })).id | ||
46 | |||
47 | await waitJobs(servers) | ||
48 | }) | ||
49 | |||
50 | describe('When listing redundancies', function () { | ||
51 | const path = '/api/v1/server/redundancy/videos' | ||
52 | |||
53 | let url: string | ||
54 | let token: string | ||
55 | |||
56 | before(function () { | ||
57 | url = servers[0].url | ||
58 | token = servers[0].accessToken | ||
59 | }) | ||
60 | |||
61 | it('Should fail with an invalid token', async function () { | ||
62 | await makeGetRequest({ url, path, token: 'fake_token', statusCodeExpected: 401 }) | ||
63 | }) | ||
64 | |||
65 | it('Should fail if the user is not an administrator', async function () { | ||
66 | await makeGetRequest({ url, path, token: userAccessToken, statusCodeExpected: 403 }) | ||
67 | }) | ||
68 | |||
69 | it('Should fail with a bad start pagination', async function () { | ||
70 | await checkBadStartPagination(url, path, servers[0].accessToken) | ||
71 | }) | ||
72 | |||
73 | it('Should fail with a bad count pagination', async function () { | ||
74 | await checkBadCountPagination(url, path, servers[0].accessToken) | ||
75 | }) | ||
76 | |||
77 | it('Should fail with an incorrect sort', async function () { | ||
78 | await checkBadSortPagination(url, path, servers[0].accessToken) | ||
79 | }) | ||
80 | |||
81 | it('Should fail with a bad target', async function () { | ||
82 | await makeGetRequest({ url, path, token, query: { target: 'bad target' } }) | ||
83 | }) | ||
84 | |||
85 | it('Should fail without target', async function () { | ||
86 | await makeGetRequest({ url, path, token }) | ||
87 | }) | ||
88 | |||
89 | it('Should succeed with the correct params', async function () { | ||
90 | await makeGetRequest({ url, path, token, query: { target: 'my-videos' }, statusCodeExpected: 200 }) | ||
91 | }) | ||
92 | }) | ||
93 | |||
94 | describe('When manually adding a redundancy', function () { | ||
95 | const path = '/api/v1/server/redundancy/videos' | ||
96 | |||
97 | let url: string | ||
98 | let token: string | ||
99 | |||
100 | before(function () { | ||
101 | url = servers[0].url | ||
102 | token = servers[0].accessToken | ||
103 | }) | ||
104 | |||
105 | it('Should fail with an invalid token', async function () { | ||
106 | await makePostBodyRequest({ url, path, token: 'fake_token', statusCodeExpected: 401 }) | ||
107 | }) | ||
108 | |||
109 | it('Should fail if the user is not an administrator', async function () { | ||
110 | await makePostBodyRequest({ url, path, token: userAccessToken, statusCodeExpected: 403 }) | ||
111 | }) | ||
112 | |||
113 | it('Should fail without a video id', async function () { | ||
114 | await makePostBodyRequest({ url, path, token }) | ||
115 | }) | ||
116 | |||
117 | it('Should fail with an incorrect video id', async function () { | ||
118 | await makePostBodyRequest({ url, path, token, fields: { videoId: 'peertube' } }) | ||
119 | }) | ||
120 | |||
121 | it('Should fail with a not found video id', async function () { | ||
122 | await makePostBodyRequest({ url, path, token, fields: { videoId: 6565 }, statusCodeExpected: 404 }) | ||
123 | }) | ||
124 | |||
125 | it('Should fail with a local a video id', async function () { | ||
126 | await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdLocal } }) | ||
127 | }) | ||
128 | |||
129 | it('Should succeed with the correct params', async function () { | ||
130 | await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdRemote }, statusCodeExpected: 204 }) | ||
131 | }) | ||
132 | |||
133 | it('Should fail if the video is already duplicated', async function () { | ||
134 | this.timeout(30000) | ||
135 | |||
136 | await waitJobs(servers) | ||
137 | |||
138 | await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdRemote }, statusCodeExpected: 409 }) | ||
139 | }) | ||
140 | }) | ||
141 | |||
142 | describe('When manually removing a redundancy', function () { | ||
143 | const path = '/api/v1/server/redundancy/videos/' | ||
144 | |||
145 | let url: string | ||
146 | let token: string | ||
147 | |||
148 | before(function () { | ||
149 | url = servers[0].url | ||
150 | token = servers[0].accessToken | ||
151 | }) | ||
152 | |||
153 | it('Should fail with an invalid token', async function () { | ||
154 | await makeDeleteRequest({ url, path: path + '1', token: 'fake_token', statusCodeExpected: 401 }) | ||
155 | }) | ||
156 | |||
157 | it('Should fail if the user is not an administrator', async function () { | ||
158 | await makeDeleteRequest({ url, path: path + '1', token: userAccessToken, statusCodeExpected: 403 }) | ||
159 | }) | ||
160 | |||
161 | it('Should fail with an incorrect video id', async function () { | ||
162 | await makeDeleteRequest({ url, path: path + 'toto', token }) | ||
163 | }) | ||
164 | |||
165 | it('Should fail with a not found video redundancy', async function () { | ||
166 | await makeDeleteRequest({ url, path: path + '454545', token, statusCodeExpected: 404 }) | ||
167 | }) | ||
39 | }) | 168 | }) |
40 | 169 | ||
41 | describe('When updating redundancy', function () { | 170 | describe('When updating server redundancy', function () { |
42 | const path = '/api/v1/server/redundancy' | 171 | const path = '/api/v1/server/redundancy' |
43 | 172 | ||
44 | it('Should fail with an invalid token', async function () { | 173 | it('Should fail with an invalid token', async function () { |
diff --git a/server/tests/api/check-params/search.ts b/server/tests/api/check-params/search.ts index 8ad9d98bf..f8d0cd4ec 100644 --- a/server/tests/api/check-params/search.ts +++ b/server/tests/api/check-params/search.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/services.ts b/server/tests/api/check-params/services.ts index d15753aed..457adfaab 100644 --- a/server/tests/api/check-params/services.ts +++ b/server/tests/api/check-params/services.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/user-notifications.ts b/server/tests/api/check-params/user-notifications.ts index 3b06be7ef..2048fa667 100644 --- a/server/tests/api/check-params/user-notifications.ts +++ b/server/tests/api/check-params/user-notifications.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as io from 'socket.io-client' | 4 | import * as io from 'socket.io-client' |
diff --git a/server/tests/api/check-params/user-subscriptions.ts b/server/tests/api/check-params/user-subscriptions.ts index fa36c4078..1edba4d64 100644 --- a/server/tests/api/check-params/user-subscriptions.ts +++ b/server/tests/api/check-params/user-subscriptions.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index 5d5af284c..f448bb2a6 100644 --- a/server/tests/api/check-params/users.ts +++ b/server/tests/api/check-params/users.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { omit } from 'lodash' | 3 | import { omit } from 'lodash' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -50,6 +50,7 @@ describe('Test users API validators', function () { | |||
50 | let serverWithRegistrationDisabled: ServerInfo | 50 | let serverWithRegistrationDisabled: ServerInfo |
51 | let userAccessToken = '' | 51 | let userAccessToken = '' |
52 | let moderatorAccessToken = '' | 52 | let moderatorAccessToken = '' |
53 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
53 | let channelId: number | 54 | let channelId: number |
54 | 55 | ||
55 | // --------------------------------------------------------------- | 56 | // --------------------------------------------------------------- |
@@ -120,7 +121,7 @@ describe('Test users API validators', function () { | |||
120 | 121 | ||
121 | { | 122 | { |
122 | const res = await getMyUserInformation(server.url, server.accessToken) | 123 | const res = await getMyUserInformation(server.url, server.accessToken) |
123 | channelId = res.body.videoChannels[ 0 ].id | 124 | channelId = res.body.videoChannels[0].id |
124 | } | 125 | } |
125 | 126 | ||
126 | { | 127 | { |
@@ -529,7 +530,7 @@ describe('Test users API validators', function () { | |||
529 | it('Should fail without an incorrect input file', async function () { | 530 | it('Should fail without an incorrect input file', async function () { |
530 | const fields = {} | 531 | const fields = {} |
531 | const attaches = { | 532 | const attaches = { |
532 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') | 533 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') |
533 | } | 534 | } |
534 | await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) | 535 | await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) |
535 | }) | 536 | }) |
@@ -537,7 +538,7 @@ describe('Test users API validators', function () { | |||
537 | it('Should fail with a big file', async function () { | 538 | it('Should fail with a big file', async function () { |
538 | const fields = {} | 539 | const fields = {} |
539 | const attaches = { | 540 | const attaches = { |
540 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | 541 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') |
541 | } | 542 | } |
542 | await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) | 543 | await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) |
543 | }) | 544 | }) |
@@ -545,7 +546,7 @@ describe('Test users API validators', function () { | |||
545 | it('Should fail with an unauthenticated user', async function () { | 546 | it('Should fail with an unauthenticated user', async function () { |
546 | const fields = {} | 547 | const fields = {} |
547 | const attaches = { | 548 | const attaches = { |
548 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 549 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
549 | } | 550 | } |
550 | await makeUploadRequest({ | 551 | await makeUploadRequest({ |
551 | url: server.url, | 552 | url: server.url, |
@@ -559,7 +560,7 @@ describe('Test users API validators', function () { | |||
559 | it('Should succeed with the correct params', async function () { | 560 | it('Should succeed with the correct params', async function () { |
560 | const fields = {} | 561 | const fields = {} |
561 | const attaches = { | 562 | const attaches = { |
562 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 563 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
563 | } | 564 | } |
564 | await makeUploadRequest({ | 565 | await makeUploadRequest({ |
565 | url: server.url, | 566 | url: server.url, |
diff --git a/server/tests/api/check-params/video-abuses.ts b/server/tests/api/check-params/video-abuses.ts index bf29f8d4d..bea2177f3 100644 --- a/server/tests/api/check-params/video-abuses.ts +++ b/server/tests/api/check-params/video-abuses.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
@@ -126,6 +126,7 @@ describe('Test video abuses API validators', function () { | |||
126 | 126 | ||
127 | describe('When updating a video abuse', function () { | 127 | describe('When updating a video abuse', function () { |
128 | const basePath = '/api/v1/videos/' | 128 | const basePath = '/api/v1/videos/' |
129 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
129 | let path: string | 130 | let path: string |
130 | 131 | ||
131 | before(() => { | 132 | before(() => { |
@@ -163,6 +164,7 @@ describe('Test video abuses API validators', function () { | |||
163 | 164 | ||
164 | describe('When deleting a video abuse', function () { | 165 | describe('When deleting a video abuse', function () { |
165 | const basePath = '/api/v1/videos/' | 166 | const basePath = '/api/v1/videos/' |
167 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
166 | let path: string | 168 | let path: string |
167 | 169 | ||
168 | before(() => { | 170 | before(() => { |
diff --git a/server/tests/api/check-params/video-blacklist.ts b/server/tests/api/check-params/video-blacklist.ts index 6466888fb..145f43980 100644 --- a/server/tests/api/check-params/video-blacklist.ts +++ b/server/tests/api/check-params/video-blacklist.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
@@ -7,25 +7,24 @@ import { | |||
7 | createUser, | 7 | createUser, |
8 | doubleFollow, | 8 | doubleFollow, |
9 | flushAndRunMultipleServers, | 9 | flushAndRunMultipleServers, |
10 | flushTests, | ||
11 | getBlacklistedVideosList, | 10 | getBlacklistedVideosList, |
12 | getVideo, | 11 | getVideo, |
13 | getVideoWithToken, | 12 | getVideoWithToken, |
14 | killallServers, | ||
15 | makePostBodyRequest, | 13 | makePostBodyRequest, |
16 | makePutBodyRequest, | 14 | makePutBodyRequest, |
17 | removeVideoFromBlacklist, | 15 | removeVideoFromBlacklist, |
18 | ServerInfo, | 16 | ServerInfo, |
19 | setAccessTokensToServers, | 17 | setAccessTokensToServers, |
20 | uploadVideo, | 18 | uploadVideo, |
21 | userLogin, waitJobs | 19 | userLogin, |
20 | waitJobs | ||
22 | } from '../../../../shared/extra-utils' | 21 | } from '../../../../shared/extra-utils' |
23 | import { | 22 | import { |
24 | checkBadCountPagination, | 23 | checkBadCountPagination, |
25 | checkBadSortPagination, | 24 | checkBadSortPagination, |
26 | checkBadStartPagination | 25 | checkBadStartPagination |
27 | } from '../../../../shared/extra-utils/requests/check-api-params' | 26 | } from '../../../../shared/extra-utils/requests/check-api-params' |
28 | import { VideoDetails, VideoBlacklistType } from '../../../../shared/models/videos' | 27 | import { VideoBlacklistType, VideoDetails } from '../../../../shared/models/videos' |
29 | import { expect } from 'chai' | 28 | import { expect } from 'chai' |
30 | 29 | ||
31 | describe('Test video blacklist API validators', function () { | 30 | describe('Test video blacklist API validators', function () { |
@@ -48,14 +47,14 @@ describe('Test video blacklist API validators', function () { | |||
48 | { | 47 | { |
49 | const username = 'user1' | 48 | const username = 'user1' |
50 | const password = 'my super password' | 49 | const password = 'my super password' |
51 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: username, password: password }) | 50 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: username, password: password }) |
52 | userAccessToken1 = await userLogin(servers[0], { username, password }) | 51 | userAccessToken1 = await userLogin(servers[0], { username, password }) |
53 | } | 52 | } |
54 | 53 | ||
55 | { | 54 | { |
56 | const username = 'user2' | 55 | const username = 'user2' |
57 | const password = 'my super password' | 56 | const password = 'my super password' |
58 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: username, password: password }) | 57 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: username, password: password }) |
59 | userAccessToken2 = await userLogin(servers[0], { username, password }) | 58 | userAccessToken2 = await userLogin(servers[0], { username, password }) |
60 | } | 59 | } |
61 | 60 | ||
@@ -120,7 +119,7 @@ describe('Test video blacklist API validators', function () { | |||
120 | 119 | ||
121 | it('Should succeed with the correct params', async function () { | 120 | it('Should succeed with the correct params', async function () { |
122 | const path = basePath + servers[0].video.uuid + '/blacklist' | 121 | const path = basePath + servers[0].video.uuid + '/blacklist' |
123 | const fields = { } | 122 | const fields = {} |
124 | 123 | ||
125 | await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields, statusCodeExpected: 204 }) | 124 | await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields, statusCodeExpected: 204 }) |
126 | }) | 125 | }) |
diff --git a/server/tests/api/check-params/video-captions.ts b/server/tests/api/check-params/video-captions.ts index 6ddc20d69..a5f5c3322 100644 --- a/server/tests/api/check-params/video-captions.ts +++ b/server/tests/api/check-params/video-captions.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
@@ -50,7 +50,7 @@ describe('Test video captions API validator', function () { | |||
50 | describe('When adding video caption', function () { | 50 | describe('When adding video caption', function () { |
51 | const fields = { } | 51 | const fields = { } |
52 | const attaches = { | 52 | const attaches = { |
53 | 'captionfile': join(__dirname, '..', '..', 'fixtures', 'subtitle-good1.vtt') | 53 | captionfile: join(__dirname, '..', '..', 'fixtures', 'subtitle-good1.vtt') |
54 | } | 54 | } |
55 | 55 | ||
56 | it('Should fail without a valid uuid', async function () { | 56 | it('Should fail without a valid uuid', async function () { |
diff --git a/server/tests/api/check-params/video-channels.ts b/server/tests/api/check-params/video-channels.ts index de88298d1..2795ad7d5 100644 --- a/server/tests/api/check-params/video-channels.ts +++ b/server/tests/api/check-params/video-channels.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import { omit } from 'lodash' | 4 | import { omit } from 'lodash' |
@@ -243,7 +243,7 @@ describe('Test video channels API validator', function () { | |||
243 | it('Should fail with an incorrect input file', async function () { | 243 | it('Should fail with an incorrect input file', async function () { |
244 | const fields = {} | 244 | const fields = {} |
245 | const attaches = { | 245 | const attaches = { |
246 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') | 246 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') |
247 | } | 247 | } |
248 | await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches }) | 248 | await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches }) |
249 | }) | 249 | }) |
@@ -251,7 +251,7 @@ describe('Test video channels API validator', function () { | |||
251 | it('Should fail with a big file', async function () { | 251 | it('Should fail with a big file', async function () { |
252 | const fields = {} | 252 | const fields = {} |
253 | const attaches = { | 253 | const attaches = { |
254 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | 254 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') |
255 | } | 255 | } |
256 | await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches }) | 256 | await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches }) |
257 | }) | 257 | }) |
@@ -259,7 +259,7 @@ describe('Test video channels API validator', function () { | |||
259 | it('Should fail with an unauthenticated user', async function () { | 259 | it('Should fail with an unauthenticated user', async function () { |
260 | const fields = {} | 260 | const fields = {} |
261 | const attaches = { | 261 | const attaches = { |
262 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 262 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
263 | } | 263 | } |
264 | await makeUploadRequest({ | 264 | await makeUploadRequest({ |
265 | url: server.url, | 265 | url: server.url, |
@@ -273,7 +273,7 @@ describe('Test video channels API validator', function () { | |||
273 | it('Should succeed with the correct params', async function () { | 273 | it('Should succeed with the correct params', async function () { |
274 | const fields = {} | 274 | const fields = {} |
275 | const attaches = { | 275 | const attaches = { |
276 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 276 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
277 | } | 277 | } |
278 | await makeUploadRequest({ | 278 | await makeUploadRequest({ |
279 | url: server.url, | 279 | url: server.url, |
@@ -324,7 +324,7 @@ describe('Test video channels API validator', function () { | |||
324 | }) | 324 | }) |
325 | 325 | ||
326 | it('Should fail with an unknown video channel id', async function () { | 326 | it('Should fail with an unknown video channel id', async function () { |
327 | await deleteVideoChannel(server.url, server.accessToken,'super_channel2', 404) | 327 | await deleteVideoChannel(server.url, server.accessToken, 'super_channel2', 404) |
328 | }) | 328 | }) |
329 | 329 | ||
330 | it('Should succeed with the correct parameters', async function () { | 330 | it('Should succeed with the correct parameters', async function () { |
diff --git a/server/tests/api/check-params/video-comments.ts b/server/tests/api/check-params/video-comments.ts index 5cf90bacc..e67cc01fa 100644 --- a/server/tests/api/check-params/video-comments.ts +++ b/server/tests/api/check-params/video-comments.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/check-params/video-imports.ts b/server/tests/api/check-params/video-imports.ts index 231d5cc85..dbea39c48 100644 --- a/server/tests/api/check-params/video-imports.ts +++ b/server/tests/api/check-params/video-imports.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { omit } from 'lodash' | 3 | import { omit } from 'lodash' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -29,6 +29,7 @@ describe('Test video imports API validator', function () { | |||
29 | const path = '/api/v1/videos/imports' | 29 | const path = '/api/v1/videos/imports' |
30 | let server: ServerInfo | 30 | let server: ServerInfo |
31 | let userAccessToken = '' | 31 | let userAccessToken = '' |
32 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
32 | let accountName: string | 33 | let accountName: string |
33 | let channelId: number | 34 | let channelId: number |
34 | 35 | ||
@@ -48,7 +49,7 @@ describe('Test video imports API validator', function () { | |||
48 | 49 | ||
49 | { | 50 | { |
50 | const res = await getMyUserInformation(server.url, server.accessToken) | 51 | const res = await getMyUserInformation(server.url, server.accessToken) |
51 | channelId = res.body.videoChannels[ 0 ].id | 52 | channelId = res.body.videoChannels[0].id |
52 | accountName = res.body.account.name + '@' + res.body.account.host | 53 | accountName = res.body.account.name + '@' + res.body.account.host |
53 | } | 54 | } |
54 | }) | 55 | }) |
@@ -196,7 +197,7 @@ describe('Test video imports API validator', function () { | |||
196 | it('Should fail with an incorrect thumbnail file', async function () { | 197 | it('Should fail with an incorrect thumbnail file', async function () { |
197 | const fields = baseCorrectParams | 198 | const fields = baseCorrectParams |
198 | const attaches = { | 199 | const attaches = { |
199 | 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 200 | thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
200 | } | 201 | } |
201 | 202 | ||
202 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | 203 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) |
@@ -205,7 +206,7 @@ describe('Test video imports API validator', function () { | |||
205 | it('Should fail with a big thumbnail file', async function () { | 206 | it('Should fail with a big thumbnail file', async function () { |
206 | const fields = baseCorrectParams | 207 | const fields = baseCorrectParams |
207 | const attaches = { | 208 | const attaches = { |
208 | 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | 209 | thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') |
209 | } | 210 | } |
210 | 211 | ||
211 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | 212 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) |
@@ -214,7 +215,7 @@ describe('Test video imports API validator', function () { | |||
214 | it('Should fail with an incorrect preview file', async function () { | 215 | it('Should fail with an incorrect preview file', async function () { |
215 | const fields = baseCorrectParams | 216 | const fields = baseCorrectParams |
216 | const attaches = { | 217 | const attaches = { |
217 | 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 218 | previewfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
218 | } | 219 | } |
219 | 220 | ||
220 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | 221 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) |
@@ -223,7 +224,7 @@ describe('Test video imports API validator', function () { | |||
223 | it('Should fail with a big preview file', async function () { | 224 | it('Should fail with a big preview file', async function () { |
224 | const fields = baseCorrectParams | 225 | const fields = baseCorrectParams |
225 | const attaches = { | 226 | const attaches = { |
226 | 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | 227 | previewfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') |
227 | } | 228 | } |
228 | 229 | ||
229 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | 230 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) |
@@ -232,7 +233,7 @@ describe('Test video imports API validator', function () { | |||
232 | it('Should fail with an invalid torrent file', async function () { | 233 | it('Should fail with an invalid torrent file', async function () { |
233 | const fields = omit(baseCorrectParams, 'targetUrl') | 234 | const fields = omit(baseCorrectParams, 'targetUrl') |
234 | const attaches = { | 235 | const attaches = { |
235 | 'torrentfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | 236 | torrentfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') |
236 | } | 237 | } |
237 | 238 | ||
238 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | 239 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) |
@@ -303,7 +304,7 @@ describe('Test video imports API validator', function () { | |||
303 | 304 | ||
304 | fields = omit(fields, 'magnetUri') | 305 | fields = omit(fields, 'magnetUri') |
305 | const attaches = { | 306 | const attaches = { |
306 | 'torrentfile': join(__dirname, '..', '..', 'fixtures', 'video-720p.torrent') | 307 | torrentfile: join(__dirname, '..', '..', 'fixtures', 'video-720p.torrent') |
307 | } | 308 | } |
308 | 309 | ||
309 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches, statusCodeExpected: 409 }) | 310 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches, statusCodeExpected: 409 }) |
diff --git a/server/tests/api/check-params/video-playlists.ts b/server/tests/api/check-params/video-playlists.ts index df158f3b1..0410e737a 100644 --- a/server/tests/api/check-params/video-playlists.ts +++ b/server/tests/api/check-params/video-playlists.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
@@ -36,6 +36,7 @@ describe('Test video playlists API validator', function () { | |||
36 | let privatePlaylistUUID: string | 36 | let privatePlaylistUUID: string |
37 | let watchLaterPlaylistId: number | 37 | let watchLaterPlaylistId: number |
38 | let videoId: number | 38 | let videoId: number |
39 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
39 | let videoId2: number | 40 | let videoId2: number |
40 | let playlistElementId: number | 41 | let playlistElementId: number |
41 | 42 | ||
@@ -449,7 +450,7 @@ describe('Test video playlists API validator', function () { | |||
449 | videoId3 = (await uploadVideoAndGetId({ server, videoName: 'video 3' })).id | 450 | videoId3 = (await uploadVideoAndGetId({ server, videoName: 'video 3' })).id |
450 | videoId4 = (await uploadVideoAndGetId({ server, videoName: 'video 4' })).id | 451 | videoId4 = (await uploadVideoAndGetId({ server, videoName: 'video 4' })).id |
451 | 452 | ||
452 | for (let id of [ videoId3, videoId4 ]) { | 453 | for (const id of [ videoId3, videoId4 ]) { |
453 | await addVideoInPlaylist({ | 454 | await addVideoInPlaylist({ |
454 | url: server.url, | 455 | url: server.url, |
455 | token: server.accessToken, | 456 | token: server.accessToken, |
@@ -476,7 +477,7 @@ describe('Test video playlists API validator', function () { | |||
476 | } | 477 | } |
477 | 478 | ||
478 | { | 479 | { |
479 | const params = getBase({}, { playlistId: 42, expectedStatus: 404 }) | 480 | const params = getBase({}, { playlistId: 42, expectedStatus: 404 }) |
480 | await reorderVideosPlaylist(params) | 481 | await reorderVideosPlaylist(params) |
481 | } | 482 | } |
482 | }) | 483 | }) |
diff --git a/server/tests/api/check-params/videos-filter.ts b/server/tests/api/check-params/videos-filter.ts index 811756745..ec8654db2 100644 --- a/server/tests/api/check-params/videos-filter.ts +++ b/server/tests/api/check-params/videos-filter.ts | |||
@@ -1,10 +1,9 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
5 | cleanupTests, | 5 | cleanupTests, |
6 | createUser, | 6 | createUser, |
7 | createVideoPlaylist, | ||
8 | flushAndRunServer, | 7 | flushAndRunServer, |
9 | makeGetRequest, | 8 | makeGetRequest, |
10 | ServerInfo, | 9 | ServerInfo, |
@@ -13,7 +12,6 @@ import { | |||
13 | userLogin | 12 | userLogin |
14 | } from '../../../../shared/extra-utils' | 13 | } from '../../../../shared/extra-utils' |
15 | import { UserRole } from '../../../../shared/models/users' | 14 | import { UserRole } from '../../../../shared/models/users' |
16 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' | ||
17 | 15 | ||
18 | async function testEndpoints (server: ServerInfo, token: string, filter: string, statusCodeExpected: number) { | 16 | async function testEndpoints (server: ServerInfo, token: string, filter: string, statusCodeExpected: number) { |
19 | const paths = [ | 17 | const paths = [ |
@@ -77,7 +75,7 @@ describe('Test videos filters', function () { | |||
77 | }) | 75 | }) |
78 | 76 | ||
79 | it('Should succeed with a good filter', async function () { | 77 | it('Should succeed with a good filter', async function () { |
80 | await testEndpoints(server, server.accessToken,'local', 200) | 78 | await testEndpoints(server, server.accessToken, 'local', 200) |
81 | }) | 79 | }) |
82 | 80 | ||
83 | it('Should fail to list all-local with a simple user', async function () { | 81 | it('Should fail to list all-local with a simple user', async function () { |
diff --git a/server/tests/api/check-params/videos-history.ts b/server/tests/api/check-params/videos-history.ts index 3739e3fad..941f62654 100644 --- a/server/tests/api/check-params/videos-history.ts +++ b/server/tests/api/check-params/videos-history.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | ||
4 | import 'mocha' | 3 | import 'mocha' |
5 | import { | 4 | import { |
6 | checkBadCountPagination, | 5 | checkBadCountPagination, |
@@ -15,12 +14,10 @@ import { | |||
15 | uploadVideo | 14 | uploadVideo |
16 | } from '../../../../shared/extra-utils' | 15 | } from '../../../../shared/extra-utils' |
17 | 16 | ||
18 | const expect = chai.expect | ||
19 | |||
20 | describe('Test videos history API validator', function () { | 17 | describe('Test videos history API validator', function () { |
18 | const myHistoryPath = '/api/v1/users/me/history/videos' | ||
19 | const myHistoryRemove = myHistoryPath + '/remove' | ||
21 | let watchingPath: string | 20 | let watchingPath: string |
22 | let myHistoryPath = '/api/v1/users/me/history/videos' | ||
23 | let myHistoryRemove = myHistoryPath + '/remove' | ||
24 | let server: ServerInfo | 21 | let server: ServerInfo |
25 | 22 | ||
26 | // --------------------------------------------------------------- | 23 | // --------------------------------------------------------------- |
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts index 16ef1c505..0d4665954 100644 --- a/server/tests/api/check-params/videos.ts +++ b/server/tests/api/check-params/videos.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import { omit } from 'lodash' | 4 | import { omit } from 'lodash' |
@@ -56,8 +56,8 @@ describe('Test videos API validator', function () { | |||
56 | 56 | ||
57 | { | 57 | { |
58 | const res = await getMyUserInformation(server.url, server.accessToken) | 58 | const res = await getMyUserInformation(server.url, server.accessToken) |
59 | channelId = res.body.videoChannels[ 0 ].id | 59 | channelId = res.body.videoChannels[0].id |
60 | channelName = res.body.videoChannels[ 0 ].name | 60 | channelName = res.body.videoChannels[0].name |
61 | accountName = res.body.account.name + '@' + res.body.account.host | 61 | accountName = res.body.account.name + '@' + res.body.account.host |
62 | } | 62 | } |
63 | }) | 63 | }) |
@@ -182,7 +182,7 @@ describe('Test videos API validator', function () { | |||
182 | describe('When adding a video', function () { | 182 | describe('When adding a video', function () { |
183 | let baseCorrectParams | 183 | let baseCorrectParams |
184 | const baseCorrectAttaches = { | 184 | const baseCorrectAttaches = { |
185 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.webm') | 185 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm') |
186 | } | 186 | } |
187 | 187 | ||
188 | before(function () { | 188 | before(function () { |
@@ -330,7 +330,7 @@ describe('Test videos API validator', function () { | |||
330 | }) | 330 | }) |
331 | 331 | ||
332 | it('Should fail with a bad originally published at attribute', async function () { | 332 | it('Should fail with a bad originally published at attribute', async function () { |
333 | const fields = immutableAssign(baseCorrectParams, { 'originallyPublishedAt': 'toto' }) | 333 | const fields = immutableAssign(baseCorrectParams, { originallyPublishedAt: 'toto' }) |
334 | const attaches = baseCorrectAttaches | 334 | const attaches = baseCorrectAttaches |
335 | 335 | ||
336 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 336 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -345,12 +345,12 @@ describe('Test videos API validator', function () { | |||
345 | it('Should fail with an incorrect input file', async function () { | 345 | it('Should fail with an incorrect input file', async function () { |
346 | const fields = baseCorrectParams | 346 | const fields = baseCorrectParams |
347 | let attaches = { | 347 | let attaches = { |
348 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') | 348 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') |
349 | } | 349 | } |
350 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 350 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
351 | 351 | ||
352 | attaches = { | 352 | attaches = { |
353 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') | 353 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') |
354 | } | 354 | } |
355 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 355 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
356 | }) | 356 | }) |
@@ -358,8 +358,8 @@ describe('Test videos API validator', function () { | |||
358 | it('Should fail with an incorrect thumbnail file', async function () { | 358 | it('Should fail with an incorrect thumbnail file', async function () { |
359 | const fields = baseCorrectParams | 359 | const fields = baseCorrectParams |
360 | const attaches = { | 360 | const attaches = { |
361 | 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png'), | 361 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png'), |
362 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 362 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
363 | } | 363 | } |
364 | 364 | ||
365 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 365 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -368,8 +368,8 @@ describe('Test videos API validator', function () { | |||
368 | it('Should fail with a big thumbnail file', async function () { | 368 | it('Should fail with a big thumbnail file', async function () { |
369 | const fields = baseCorrectParams | 369 | const fields = baseCorrectParams |
370 | const attaches = { | 370 | const attaches = { |
371 | 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'), | 371 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'), |
372 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 372 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
373 | } | 373 | } |
374 | 374 | ||
375 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 375 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -378,8 +378,8 @@ describe('Test videos API validator', function () { | |||
378 | it('Should fail with an incorrect preview file', async function () { | 378 | it('Should fail with an incorrect preview file', async function () { |
379 | const fields = baseCorrectParams | 379 | const fields = baseCorrectParams |
380 | const attaches = { | 380 | const attaches = { |
381 | 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png'), | 381 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png'), |
382 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 382 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
383 | } | 383 | } |
384 | 384 | ||
385 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 385 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -388,8 +388,8 @@ describe('Test videos API validator', function () { | |||
388 | it('Should fail with a big preview file', async function () { | 388 | it('Should fail with a big preview file', async function () { |
389 | const fields = baseCorrectParams | 389 | const fields = baseCorrectParams |
390 | const attaches = { | 390 | const attaches = { |
391 | 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'), | 391 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'), |
392 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 392 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
393 | } | 393 | } |
394 | 394 | ||
395 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 395 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -566,7 +566,7 @@ describe('Test videos API validator', function () { | |||
566 | it('Should fail with an incorrect thumbnail file', async function () { | 566 | it('Should fail with an incorrect thumbnail file', async function () { |
567 | const fields = baseCorrectParams | 567 | const fields = baseCorrectParams |
568 | const attaches = { | 568 | const attaches = { |
569 | 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png') | 569 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png') |
570 | } | 570 | } |
571 | 571 | ||
572 | await makeUploadRequest({ | 572 | await makeUploadRequest({ |
@@ -582,7 +582,7 @@ describe('Test videos API validator', function () { | |||
582 | it('Should fail with a big thumbnail file', async function () { | 582 | it('Should fail with a big thumbnail file', async function () { |
583 | const fields = baseCorrectParams | 583 | const fields = baseCorrectParams |
584 | const attaches = { | 584 | const attaches = { |
585 | 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png') | 585 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png') |
586 | } | 586 | } |
587 | 587 | ||
588 | await makeUploadRequest({ | 588 | await makeUploadRequest({ |
@@ -598,7 +598,7 @@ describe('Test videos API validator', function () { | |||
598 | it('Should fail with an incorrect preview file', async function () { | 598 | it('Should fail with an incorrect preview file', async function () { |
599 | const fields = baseCorrectParams | 599 | const fields = baseCorrectParams |
600 | const attaches = { | 600 | const attaches = { |
601 | 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png') | 601 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png') |
602 | } | 602 | } |
603 | 603 | ||
604 | await makeUploadRequest({ | 604 | await makeUploadRequest({ |
@@ -614,7 +614,7 @@ describe('Test videos API validator', function () { | |||
614 | it('Should fail with a big preview file', async function () { | 614 | it('Should fail with a big preview file', async function () { |
615 | const fields = baseCorrectParams | 615 | const fields = baseCorrectParams |
616 | const attaches = { | 616 | const attaches = { |
617 | 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png') | 617 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png') |
618 | } | 618 | } |
619 | 619 | ||
620 | await makeUploadRequest({ | 620 | await makeUploadRequest({ |
diff --git a/server/tests/api/notifications/user-notifications.ts b/server/tests/api/notifications/user-notifications.ts index 15a34f5aa..2a632e16f 100644 --- a/server/tests/api/notifications/user-notifications.ts +++ b/server/tests/api/notifications/user-notifications.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -74,7 +74,7 @@ async function uploadVideoByRemoteAccount (servers: ServerInfo[], additionalPara | |||
74 | const name = 'remote video ' + uuidv4() | 74 | const name = 'remote video ' + uuidv4() |
75 | 75 | ||
76 | const data = Object.assign({ name }, additionalParams) | 76 | const data = Object.assign({ name }, additionalParams) |
77 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, data) | 77 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, data) |
78 | 78 | ||
79 | await waitJobs(servers) | 79 | await waitJobs(servers) |
80 | 80 | ||
@@ -85,7 +85,7 @@ async function uploadVideoByLocalAccount (servers: ServerInfo[], additionalParam | |||
85 | const name = 'local video ' + uuidv4() | 85 | const name = 'local video ' + uuidv4() |
86 | 86 | ||
87 | const data = Object.assign({ name }, additionalParams) | 87 | const data = Object.assign({ name }, additionalParams) |
88 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, data) | 88 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, data) |
89 | 89 | ||
90 | await waitJobs(servers) | 90 | await waitJobs(servers) |
91 | 91 | ||
@@ -95,9 +95,9 @@ async function uploadVideoByLocalAccount (servers: ServerInfo[], additionalParam | |||
95 | describe('Test users notifications', function () { | 95 | describe('Test users notifications', function () { |
96 | let servers: ServerInfo[] = [] | 96 | let servers: ServerInfo[] = [] |
97 | let userAccessToken: string | 97 | let userAccessToken: string |
98 | let userNotifications: UserNotification[] = [] | 98 | const userNotifications: UserNotification[] = [] |
99 | let adminNotifications: UserNotification[] = [] | 99 | const adminNotifications: UserNotification[] = [] |
100 | let adminNotificationsServer2: UserNotification[] = [] | 100 | const adminNotificationsServer2: UserNotification[] = [] |
101 | const emails: object[] = [] | 101 | const emails: object[] = [] |
102 | let channelId: number | 102 | let channelId: number |
103 | 103 | ||
@@ -142,8 +142,8 @@ describe('Test users notifications', function () { | |||
142 | password: 'super password' | 142 | password: 'super password' |
143 | } | 143 | } |
144 | await createUser({ | 144 | await createUser({ |
145 | url: servers[ 0 ].url, | 145 | url: servers[0].url, |
146 | accessToken: servers[ 0 ].accessToken, | 146 | accessToken: servers[0].accessToken, |
147 | username: user.username, | 147 | username: user.username, |
148 | password: user.password, | 148 | password: user.password, |
149 | videoQuota: 10 * 1000 * 1000 | 149 | videoQuota: 10 * 1000 * 1000 |
@@ -155,15 +155,15 @@ describe('Test users notifications', function () { | |||
155 | await updateMyNotificationSettings(servers[1].url, servers[1].accessToken, allNotificationSettings) | 155 | await updateMyNotificationSettings(servers[1].url, servers[1].accessToken, allNotificationSettings) |
156 | 156 | ||
157 | { | 157 | { |
158 | const socket = getUserNotificationSocket(servers[ 0 ].url, userAccessToken) | 158 | const socket = getUserNotificationSocket(servers[0].url, userAccessToken) |
159 | socket.on('new-notification', n => userNotifications.push(n)) | 159 | socket.on('new-notification', n => userNotifications.push(n)) |
160 | } | 160 | } |
161 | { | 161 | { |
162 | const socket = getUserNotificationSocket(servers[ 0 ].url, servers[0].accessToken) | 162 | const socket = getUserNotificationSocket(servers[0].url, servers[0].accessToken) |
163 | socket.on('new-notification', n => adminNotifications.push(n)) | 163 | socket.on('new-notification', n => adminNotifications.push(n)) |
164 | } | 164 | } |
165 | { | 165 | { |
166 | const socket = getUserNotificationSocket(servers[ 1 ].url, servers[1].accessToken) | 166 | const socket = getUserNotificationSocket(servers[1].url, servers[1].accessToken) |
167 | socket.on('new-notification', n => adminNotificationsServer2.push(n)) | 167 | socket.on('new-notification', n => adminNotificationsServer2.push(n)) |
168 | } | 168 | } |
169 | 169 | ||
@@ -190,7 +190,7 @@ describe('Test users notifications', function () { | |||
190 | 190 | ||
191 | await uploadVideoByLocalAccount(servers) | 191 | await uploadVideoByLocalAccount(servers) |
192 | 192 | ||
193 | const notification = await getLastNotification(servers[ 0 ].url, userAccessToken) | 193 | const notification = await getLastNotification(servers[0].url, userAccessToken) |
194 | expect(notification).to.be.undefined | 194 | expect(notification).to.be.undefined |
195 | 195 | ||
196 | expect(emails).to.have.lengthOf(0) | 196 | expect(emails).to.have.lengthOf(0) |
@@ -221,7 +221,7 @@ describe('Test users notifications', function () { | |||
221 | this.timeout(20000) | 221 | this.timeout(20000) |
222 | 222 | ||
223 | // In 2 seconds | 223 | // In 2 seconds |
224 | let updateAt = new Date(new Date().getTime() + 2000) | 224 | const updateAt = new Date(new Date().getTime() + 2000) |
225 | 225 | ||
226 | const data = { | 226 | const data = { |
227 | privacy: VideoPrivacy.PRIVATE, | 227 | privacy: VideoPrivacy.PRIVATE, |
@@ -240,7 +240,7 @@ describe('Test users notifications', function () { | |||
240 | this.timeout(50000) | 240 | this.timeout(50000) |
241 | 241 | ||
242 | // In 2 seconds | 242 | // In 2 seconds |
243 | let updateAt = new Date(new Date().getTime() + 2000) | 243 | const updateAt = new Date(new Date().getTime() + 2000) |
244 | 244 | ||
245 | const data = { | 245 | const data = { |
246 | privacy: VideoPrivacy.PRIVATE, | 246 | privacy: VideoPrivacy.PRIVATE, |
@@ -259,7 +259,7 @@ describe('Test users notifications', function () { | |||
259 | it('Should not send a notification before the video is published', async function () { | 259 | it('Should not send a notification before the video is published', async function () { |
260 | this.timeout(20000) | 260 | this.timeout(20000) |
261 | 261 | ||
262 | let updateAt = new Date(new Date().getTime() + 1000000) | 262 | const updateAt = new Date(new Date().getTime() + 1000000) |
263 | 263 | ||
264 | const data = { | 264 | const data = { |
265 | privacy: VideoPrivacy.PRIVATE, | 265 | privacy: VideoPrivacy.PRIVATE, |
@@ -386,7 +386,7 @@ describe('Test users notifications', function () { | |||
386 | it('Should not send a new comment notification if the account is muted', async function () { | 386 | it('Should not send a new comment notification if the account is muted', async function () { |
387 | this.timeout(10000) | 387 | this.timeout(10000) |
388 | 388 | ||
389 | await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') | 389 | await addAccountToAccountBlocklist(servers[0].url, userAccessToken, 'root') |
390 | 390 | ||
391 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: 'super video' }) | 391 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: 'super video' }) |
392 | const uuid = resVideo.body.video.uuid | 392 | const uuid = resVideo.body.video.uuid |
@@ -397,7 +397,7 @@ describe('Test users notifications', function () { | |||
397 | await wait(500) | 397 | await wait(500) |
398 | await checkNewCommentOnMyVideo(baseParams, uuid, commentId, commentId, 'absence') | 398 | await checkNewCommentOnMyVideo(baseParams, uuid, commentId, commentId, 'absence') |
399 | 399 | ||
400 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') | 400 | await removeAccountFromAccountBlocklist(servers[0].url, userAccessToken, 'root') |
401 | }) | 401 | }) |
402 | 402 | ||
403 | it('Should send a new comment notification after a local comment on my video', async function () { | 403 | it('Should send a new comment notification after a local comment on my video', async function () { |
@@ -456,9 +456,9 @@ describe('Test users notifications', function () { | |||
456 | await waitJobs(servers) | 456 | await waitJobs(servers) |
457 | 457 | ||
458 | { | 458 | { |
459 | const resThread = await addVideoCommentThread(servers[ 1 ].url, servers[ 1 ].accessToken, uuid, 'comment') | 459 | const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, 'comment') |
460 | const threadId = resThread.body.comment.id | 460 | const threadId = resThread.body.comment.id |
461 | await addVideoCommentReply(servers[ 1 ].url, servers[ 1 ].accessToken, uuid, threadId, 'reply') | 461 | await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, threadId, 'reply') |
462 | } | 462 | } |
463 | 463 | ||
464 | await waitJobs(servers) | 464 | await waitJobs(servers) |
@@ -530,7 +530,7 @@ describe('Test users notifications', function () { | |||
530 | it('Should not send a new mention notification if the account is muted', async function () { | 530 | it('Should not send a new mention notification if the account is muted', async function () { |
531 | this.timeout(10000) | 531 | this.timeout(10000) |
532 | 532 | ||
533 | await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') | 533 | await addAccountToAccountBlocklist(servers[0].url, userAccessToken, 'root') |
534 | 534 | ||
535 | const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'super video' }) | 535 | const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'super video' }) |
536 | const uuid = resVideo.body.video.uuid | 536 | const uuid = resVideo.body.video.uuid |
@@ -541,7 +541,7 @@ describe('Test users notifications', function () { | |||
541 | await wait(500) | 541 | await wait(500) |
542 | await checkCommentMention(baseParams, uuid, commentId, commentId, 'super root name', 'absence') | 542 | await checkCommentMention(baseParams, uuid, commentId, commentId, 'super root name', 'absence') |
543 | 543 | ||
544 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') | 544 | await removeAccountFromAccountBlocklist(servers[0].url, userAccessToken, 'root') |
545 | }) | 545 | }) |
546 | 546 | ||
547 | it('Should not send a new mention notification if the remote account mention a local account', async function () { | 547 | it('Should not send a new mention notification if the remote account mention a local account', async function () { |
@@ -585,7 +585,7 @@ describe('Test users notifications', function () { | |||
585 | 585 | ||
586 | await waitJobs(servers) | 586 | await waitJobs(servers) |
587 | 587 | ||
588 | const text1 = `hello @user_1@localhost:${servers[ 0 ].port} 1` | 588 | const text1 = `hello @user_1@localhost:${servers[0].port} 1` |
589 | const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, text1) | 589 | const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, text1) |
590 | const server2ThreadId = resThread.body.comment.id | 590 | const server2ThreadId = resThread.body.comment.id |
591 | 591 | ||
@@ -596,7 +596,7 @@ describe('Test users notifications', function () { | |||
596 | const server1ThreadId = resThread2.body.data[0].id | 596 | const server1ThreadId = resThread2.body.data[0].id |
597 | await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence') | 597 | await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence') |
598 | 598 | ||
599 | const text2 = `@user_1@localhost:${servers[ 0 ].port} hello 2 @root@localhost:${servers[ 0 ].port}` | 599 | const text2 = `@user_1@localhost:${servers[0].port} hello 2 @root@localhost:${servers[0].port}` |
600 | await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text2) | 600 | await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text2) |
601 | 601 | ||
602 | await waitJobs(servers) | 602 | await waitJobs(servers) |
@@ -611,7 +611,7 @@ describe('Test users notifications', function () { | |||
611 | }) | 611 | }) |
612 | }) | 612 | }) |
613 | 613 | ||
614 | describe('Video abuse for moderators notification' , function () { | 614 | describe('Video abuse for moderators notification', function () { |
615 | let baseParams: CheckerBaseParams | 615 | let baseParams: CheckerBaseParams |
616 | 616 | ||
617 | before(() => { | 617 | before(() => { |
@@ -722,7 +722,7 @@ describe('Test users notifications', function () { | |||
722 | await uploadVideoByRemoteAccount(servers, { waitTranscoding: false }) | 722 | await uploadVideoByRemoteAccount(servers, { waitTranscoding: false }) |
723 | await waitJobs(servers) | 723 | await waitJobs(servers) |
724 | 724 | ||
725 | const notification = await getLastNotification(servers[ 0 ].url, userAccessToken) | 725 | const notification = await getLastNotification(servers[0].url, userAccessToken) |
726 | if (notification) { | 726 | if (notification) { |
727 | expect(notification.type).to.not.equal(UserNotificationType.MY_VIDEO_PUBLISHED) | 727 | expect(notification.type).to.not.equal(UserNotificationType.MY_VIDEO_PUBLISHED) |
728 | } | 728 | } |
@@ -769,7 +769,7 @@ describe('Test users notifications', function () { | |||
769 | this.timeout(70000) | 769 | this.timeout(70000) |
770 | 770 | ||
771 | // In 2 seconds | 771 | // In 2 seconds |
772 | let updateAt = new Date(new Date().getTime() + 2000) | 772 | const updateAt = new Date(new Date().getTime() + 2000) |
773 | 773 | ||
774 | const data = { | 774 | const data = { |
775 | privacy: VideoPrivacy.PRIVATE, | 775 | privacy: VideoPrivacy.PRIVATE, |
@@ -787,7 +787,7 @@ describe('Test users notifications', function () { | |||
787 | it('Should not send a notification before the video is published', async function () { | 787 | it('Should not send a notification before the video is published', async function () { |
788 | this.timeout(20000) | 788 | this.timeout(20000) |
789 | 789 | ||
790 | let updateAt = new Date(new Date().getTime() + 1000000) | 790 | const updateAt = new Date(new Date().getTime() + 1000000) |
791 | 791 | ||
792 | const data = { | 792 | const data = { |
793 | privacy: VideoPrivacy.PRIVATE, | 793 | privacy: VideoPrivacy.PRIVATE, |
@@ -970,8 +970,8 @@ describe('Test users notifications', function () { | |||
970 | 970 | ||
971 | describe('New actor follow', function () { | 971 | describe('New actor follow', function () { |
972 | let baseParams: CheckerBaseParams | 972 | let baseParams: CheckerBaseParams |
973 | let myChannelName = 'super channel name' | 973 | const myChannelName = 'super channel name' |
974 | let myUserName = 'super user name' | 974 | const myUserName = 'super user name' |
975 | 975 | ||
976 | before(async () => { | 976 | before(async () => { |
977 | baseParams = { | 977 | baseParams = { |
@@ -1143,7 +1143,7 @@ describe('Test users notifications', function () { | |||
1143 | it('Should send unblacklist but not published/subscription notes after unblacklisted if scheduled update pending', async function () { | 1143 | it('Should send unblacklist but not published/subscription notes after unblacklisted if scheduled update pending', async function () { |
1144 | this.timeout(20000) | 1144 | this.timeout(20000) |
1145 | 1145 | ||
1146 | let updateAt = new Date(new Date().getTime() + 1000000) | 1146 | const updateAt = new Date(new Date().getTime() + 1000000) |
1147 | 1147 | ||
1148 | const name = 'video with auto-blacklist and future schedule ' + uuidv4() | 1148 | const name = 'video with auto-blacklist and future schedule ' + uuidv4() |
1149 | 1149 | ||
@@ -1176,7 +1176,7 @@ describe('Test users notifications', function () { | |||
1176 | this.timeout(20000) | 1176 | this.timeout(20000) |
1177 | 1177 | ||
1178 | // In 2 seconds | 1178 | // In 2 seconds |
1179 | let updateAt = new Date(new Date().getTime() + 2000) | 1179 | const updateAt = new Date(new Date().getTime() + 2000) |
1180 | 1180 | ||
1181 | const name = 'video with schedule done and still auto-blacklisted ' + uuidv4() | 1181 | const name = 'video with schedule done and still auto-blacklisted ' + uuidv4() |
1182 | 1182 | ||
@@ -1221,26 +1221,26 @@ describe('Test users notifications', function () { | |||
1221 | 1221 | ||
1222 | describe('Mark as read', function () { | 1222 | describe('Mark as read', function () { |
1223 | it('Should mark as read some notifications', async function () { | 1223 | it('Should mark as read some notifications', async function () { |
1224 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 2, 3) | 1224 | const res = await getUserNotifications(servers[0].url, userAccessToken, 2, 3) |
1225 | const ids = res.body.data.map(n => n.id) | 1225 | const ids = res.body.data.map(n => n.id) |
1226 | 1226 | ||
1227 | await markAsReadNotifications(servers[ 0 ].url, userAccessToken, ids) | 1227 | await markAsReadNotifications(servers[0].url, userAccessToken, ids) |
1228 | }) | 1228 | }) |
1229 | 1229 | ||
1230 | it('Should have the notifications marked as read', async function () { | 1230 | it('Should have the notifications marked as read', async function () { |
1231 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10) | 1231 | const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10) |
1232 | 1232 | ||
1233 | const notifications = res.body.data as UserNotification[] | 1233 | const notifications = res.body.data as UserNotification[] |
1234 | expect(notifications[ 0 ].read).to.be.false | 1234 | expect(notifications[0].read).to.be.false |
1235 | expect(notifications[ 1 ].read).to.be.false | 1235 | expect(notifications[1].read).to.be.false |
1236 | expect(notifications[ 2 ].read).to.be.true | 1236 | expect(notifications[2].read).to.be.true |
1237 | expect(notifications[ 3 ].read).to.be.true | 1237 | expect(notifications[3].read).to.be.true |
1238 | expect(notifications[ 4 ].read).to.be.true | 1238 | expect(notifications[4].read).to.be.true |
1239 | expect(notifications[ 5 ].read).to.be.false | 1239 | expect(notifications[5].read).to.be.false |
1240 | }) | 1240 | }) |
1241 | 1241 | ||
1242 | it('Should only list read notifications', async function () { | 1242 | it('Should only list read notifications', async function () { |
1243 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, false) | 1243 | const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, false) |
1244 | 1244 | ||
1245 | const notifications = res.body.data as UserNotification[] | 1245 | const notifications = res.body.data as UserNotification[] |
1246 | for (const notification of notifications) { | 1246 | for (const notification of notifications) { |
@@ -1249,7 +1249,7 @@ describe('Test users notifications', function () { | |||
1249 | }) | 1249 | }) |
1250 | 1250 | ||
1251 | it('Should only list unread notifications', async function () { | 1251 | it('Should only list unread notifications', async function () { |
1252 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, true) | 1252 | const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, true) |
1253 | 1253 | ||
1254 | const notifications = res.body.data as UserNotification[] | 1254 | const notifications = res.body.data as UserNotification[] |
1255 | for (const notification of notifications) { | 1255 | for (const notification of notifications) { |
@@ -1258,9 +1258,9 @@ describe('Test users notifications', function () { | |||
1258 | }) | 1258 | }) |
1259 | 1259 | ||
1260 | it('Should mark as read all notifications', async function () { | 1260 | it('Should mark as read all notifications', async function () { |
1261 | await markAsReadAllNotifications(servers[ 0 ].url, userAccessToken) | 1261 | await markAsReadAllNotifications(servers[0].url, userAccessToken) |
1262 | 1262 | ||
1263 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, true) | 1263 | const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, true) |
1264 | 1264 | ||
1265 | expect(res.body.total).to.equal(0) | 1265 | expect(res.body.total).to.equal(0) |
1266 | expect(res.body.data).to.have.lengthOf(0) | 1266 | expect(res.body.data).to.have.lengthOf(0) |
diff --git a/server/tests/api/redundancy/index.ts b/server/tests/api/redundancy/index.ts index 8e69b95a6..5359055b0 100644 --- a/server/tests/api/redundancy/index.ts +++ b/server/tests/api/redundancy/index.ts | |||
@@ -1 +1,2 @@ | |||
1 | import './redundancy' | 1 | import './redundancy' |
2 | import './manage-redundancy' | ||
diff --git a/server/tests/api/redundancy/manage-redundancy.ts b/server/tests/api/redundancy/manage-redundancy.ts new file mode 100644 index 000000000..4253124c8 --- /dev/null +++ b/server/tests/api/redundancy/manage-redundancy.ts | |||
@@ -0,0 +1,373 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import * as chai from 'chai' | ||
4 | import 'mocha' | ||
5 | import { | ||
6 | cleanupTests, | ||
7 | doubleFollow, | ||
8 | flushAndRunMultipleServers, | ||
9 | getLocalIdByUUID, | ||
10 | ServerInfo, | ||
11 | setAccessTokensToServers, | ||
12 | uploadVideo, | ||
13 | uploadVideoAndGetId, | ||
14 | waitUntilLog | ||
15 | } from '../../../../shared/extra-utils' | ||
16 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | ||
17 | import { addVideoRedundancy, listVideoRedundancies, removeVideoRedundancy, updateRedundancy } from '@shared/extra-utils/server/redundancy' | ||
18 | import { VideoPrivacy, VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' | ||
19 | |||
20 | const expect = chai.expect | ||
21 | |||
22 | describe('Test manage videos redundancy', function () { | ||
23 | const targets: VideoRedundanciesTarget[] = [ 'my-videos', 'remote-videos' ] | ||
24 | |||
25 | let servers: ServerInfo[] | ||
26 | let video1Server2UUID: string | ||
27 | let video2Server2UUID: string | ||
28 | let redundanciesToRemove: number[] = [] | ||
29 | |||
30 | before(async function () { | ||
31 | this.timeout(120000) | ||
32 | |||
33 | const config = { | ||
34 | transcoding: { | ||
35 | hls: { | ||
36 | enabled: true | ||
37 | } | ||
38 | }, | ||
39 | redundancy: { | ||
40 | videos: { | ||
41 | check_interval: '1 second', | ||
42 | strategies: [ | ||
43 | { | ||
44 | strategy: 'recently-added', | ||
45 | min_lifetime: '1 hour', | ||
46 | size: '10MB', | ||
47 | min_views: 0 | ||
48 | } | ||
49 | ] | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | servers = await flushAndRunMultipleServers(3, config) | ||
54 | |||
55 | // Get the access tokens | ||
56 | await setAccessTokensToServers(servers) | ||
57 | |||
58 | { | ||
59 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 server 2' }) | ||
60 | video1Server2UUID = res.body.video.uuid | ||
61 | } | ||
62 | |||
63 | { | ||
64 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 2 server 2' }) | ||
65 | video2Server2UUID = res.body.video.uuid | ||
66 | } | ||
67 | |||
68 | await waitJobs(servers) | ||
69 | |||
70 | // Server 1 and server 2 follow each other | ||
71 | await doubleFollow(servers[0], servers[1]) | ||
72 | await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, true) | ||
73 | |||
74 | await waitJobs(servers) | ||
75 | }) | ||
76 | |||
77 | it('Should not have redundancies on server 3', async function () { | ||
78 | for (const target of targets) { | ||
79 | const res = await listVideoRedundancies({ | ||
80 | url: servers[2].url, | ||
81 | accessToken: servers[2].accessToken, | ||
82 | target | ||
83 | }) | ||
84 | |||
85 | expect(res.body.total).to.equal(0) | ||
86 | expect(res.body.data).to.have.lengthOf(0) | ||
87 | } | ||
88 | }) | ||
89 | |||
90 | it('Should not have "remote-videos" redundancies on server 2', async function () { | ||
91 | this.timeout(120000) | ||
92 | |||
93 | await waitJobs(servers) | ||
94 | await waitUntilLog(servers[0], 'Duplicated ', 10) | ||
95 | await waitJobs(servers) | ||
96 | |||
97 | const res = await listVideoRedundancies({ | ||
98 | url: servers[1].url, | ||
99 | accessToken: servers[1].accessToken, | ||
100 | target: 'remote-videos' | ||
101 | }) | ||
102 | |||
103 | expect(res.body.total).to.equal(0) | ||
104 | expect(res.body.data).to.have.lengthOf(0) | ||
105 | }) | ||
106 | |||
107 | it('Should have "my-videos" redundancies on server 2', async function () { | ||
108 | this.timeout(120000) | ||
109 | |||
110 | const res = await listVideoRedundancies({ | ||
111 | url: servers[1].url, | ||
112 | accessToken: servers[1].accessToken, | ||
113 | target: 'my-videos' | ||
114 | }) | ||
115 | |||
116 | expect(res.body.total).to.equal(2) | ||
117 | |||
118 | const videos = res.body.data as VideoRedundancy[] | ||
119 | expect(videos).to.have.lengthOf(2) | ||
120 | |||
121 | const videos1 = videos.find(v => v.uuid === video1Server2UUID) | ||
122 | const videos2 = videos.find(v => v.uuid === video2Server2UUID) | ||
123 | |||
124 | expect(videos1.name).to.equal('video 1 server 2') | ||
125 | expect(videos2.name).to.equal('video 2 server 2') | ||
126 | |||
127 | expect(videos1.redundancies.files).to.have.lengthOf(4) | ||
128 | expect(videos1.redundancies.streamingPlaylists).to.have.lengthOf(1) | ||
129 | |||
130 | const redundancies = videos1.redundancies.files.concat(videos1.redundancies.streamingPlaylists) | ||
131 | |||
132 | for (const r of redundancies) { | ||
133 | expect(r.strategy).to.be.null | ||
134 | expect(r.fileUrl).to.exist | ||
135 | expect(r.createdAt).to.exist | ||
136 | expect(r.updatedAt).to.exist | ||
137 | expect(r.expiresOn).to.exist | ||
138 | } | ||
139 | }) | ||
140 | |||
141 | it('Should not have "my-videos" redundancies on server 1', async function () { | ||
142 | const res = await listVideoRedundancies({ | ||
143 | url: servers[0].url, | ||
144 | accessToken: servers[0].accessToken, | ||
145 | target: 'my-videos' | ||
146 | }) | ||
147 | |||
148 | expect(res.body.total).to.equal(0) | ||
149 | expect(res.body.data).to.have.lengthOf(0) | ||
150 | }) | ||
151 | |||
152 | it('Should have "remote-videos" redundancies on server 1', async function () { | ||
153 | this.timeout(120000) | ||
154 | |||
155 | const res = await listVideoRedundancies({ | ||
156 | url: servers[0].url, | ||
157 | accessToken: servers[0].accessToken, | ||
158 | target: 'remote-videos' | ||
159 | }) | ||
160 | |||
161 | expect(res.body.total).to.equal(2) | ||
162 | |||
163 | const videos = res.body.data as VideoRedundancy[] | ||
164 | expect(videos).to.have.lengthOf(2) | ||
165 | |||
166 | const videos1 = videos.find(v => v.uuid === video1Server2UUID) | ||
167 | const videos2 = videos.find(v => v.uuid === video2Server2UUID) | ||
168 | |||
169 | expect(videos1.name).to.equal('video 1 server 2') | ||
170 | expect(videos2.name).to.equal('video 2 server 2') | ||
171 | |||
172 | expect(videos1.redundancies.files).to.have.lengthOf(4) | ||
173 | expect(videos1.redundancies.streamingPlaylists).to.have.lengthOf(1) | ||
174 | |||
175 | const redundancies = videos1.redundancies.files.concat(videos1.redundancies.streamingPlaylists) | ||
176 | |||
177 | for (const r of redundancies) { | ||
178 | expect(r.strategy).to.equal('recently-added') | ||
179 | expect(r.fileUrl).to.exist | ||
180 | expect(r.createdAt).to.exist | ||
181 | expect(r.updatedAt).to.exist | ||
182 | expect(r.expiresOn).to.exist | ||
183 | } | ||
184 | }) | ||
185 | |||
186 | it('Should correctly paginate and sort results', async function () { | ||
187 | { | ||
188 | const res = await listVideoRedundancies({ | ||
189 | url: servers[0].url, | ||
190 | accessToken: servers[0].accessToken, | ||
191 | target: 'remote-videos', | ||
192 | sort: 'name', | ||
193 | start: 0, | ||
194 | count: 2 | ||
195 | }) | ||
196 | |||
197 | const videos = res.body.data | ||
198 | expect(videos[0].name).to.equal('video 1 server 2') | ||
199 | expect(videos[1].name).to.equal('video 2 server 2') | ||
200 | } | ||
201 | |||
202 | { | ||
203 | const res = await listVideoRedundancies({ | ||
204 | url: servers[0].url, | ||
205 | accessToken: servers[0].accessToken, | ||
206 | target: 'remote-videos', | ||
207 | sort: '-name', | ||
208 | start: 0, | ||
209 | count: 2 | ||
210 | }) | ||
211 | |||
212 | const videos = res.body.data | ||
213 | expect(videos[0].name).to.equal('video 2 server 2') | ||
214 | expect(videos[1].name).to.equal('video 1 server 2') | ||
215 | } | ||
216 | |||
217 | { | ||
218 | const res = await listVideoRedundancies({ | ||
219 | url: servers[0].url, | ||
220 | accessToken: servers[0].accessToken, | ||
221 | target: 'remote-videos', | ||
222 | sort: '-name', | ||
223 | start: 1, | ||
224 | count: 1 | ||
225 | }) | ||
226 | |||
227 | const videos = res.body.data | ||
228 | expect(videos[0].name).to.equal('video 1 server 2') | ||
229 | } | ||
230 | }) | ||
231 | |||
232 | it('Should manually add a redundancy and list it', async function () { | ||
233 | this.timeout(120000) | ||
234 | |||
235 | const uuid = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 3 server 2', privacy: VideoPrivacy.UNLISTED })).uuid | ||
236 | await waitJobs(servers) | ||
237 | const videoId = await getLocalIdByUUID(servers[0].url, uuid) | ||
238 | |||
239 | await addVideoRedundancy({ | ||
240 | url: servers[0].url, | ||
241 | accessToken: servers[0].accessToken, | ||
242 | videoId | ||
243 | }) | ||
244 | |||
245 | await waitJobs(servers) | ||
246 | await waitUntilLog(servers[0], 'Duplicated ', 15) | ||
247 | await waitJobs(servers) | ||
248 | |||
249 | { | ||
250 | const res = await listVideoRedundancies({ | ||
251 | url: servers[0].url, | ||
252 | accessToken: servers[0].accessToken, | ||
253 | target: 'remote-videos', | ||
254 | sort: '-name', | ||
255 | start: 0, | ||
256 | count: 5 | ||
257 | }) | ||
258 | |||
259 | const videos = res.body.data | ||
260 | expect(videos[0].name).to.equal('video 3 server 2') | ||
261 | |||
262 | const video = videos[0] | ||
263 | expect(video.redundancies.files).to.have.lengthOf(4) | ||
264 | expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) | ||
265 | |||
266 | const redundancies = video.redundancies.files.concat(video.redundancies.streamingPlaylists) | ||
267 | |||
268 | for (const r of redundancies) { | ||
269 | redundanciesToRemove.push(r.id) | ||
270 | |||
271 | expect(r.strategy).to.equal('manual') | ||
272 | expect(r.fileUrl).to.exist | ||
273 | expect(r.createdAt).to.exist | ||
274 | expect(r.updatedAt).to.exist | ||
275 | expect(r.expiresOn).to.be.null | ||
276 | } | ||
277 | } | ||
278 | |||
279 | const res = await listVideoRedundancies({ | ||
280 | url: servers[1].url, | ||
281 | accessToken: servers[1].accessToken, | ||
282 | target: 'my-videos', | ||
283 | sort: '-name', | ||
284 | start: 0, | ||
285 | count: 5 | ||
286 | }) | ||
287 | |||
288 | const videos = res.body.data | ||
289 | expect(videos[0].name).to.equal('video 3 server 2') | ||
290 | |||
291 | const video = videos[0] | ||
292 | expect(video.redundancies.files).to.have.lengthOf(4) | ||
293 | expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) | ||
294 | |||
295 | const redundancies = video.redundancies.files.concat(video.redundancies.streamingPlaylists) | ||
296 | |||
297 | for (const r of redundancies) { | ||
298 | expect(r.strategy).to.be.null | ||
299 | expect(r.fileUrl).to.exist | ||
300 | expect(r.createdAt).to.exist | ||
301 | expect(r.updatedAt).to.exist | ||
302 | expect(r.expiresOn).to.be.null | ||
303 | } | ||
304 | }) | ||
305 | |||
306 | it('Should manually remove a redundancy and remove it from the list', async function () { | ||
307 | this.timeout(120000) | ||
308 | |||
309 | for (const redundancyId of redundanciesToRemove) { | ||
310 | await removeVideoRedundancy({ | ||
311 | url: servers[0].url, | ||
312 | accessToken: servers[0].accessToken, | ||
313 | redundancyId | ||
314 | }) | ||
315 | } | ||
316 | |||
317 | { | ||
318 | const res = await listVideoRedundancies({ | ||
319 | url: servers[0].url, | ||
320 | accessToken: servers[0].accessToken, | ||
321 | target: 'remote-videos', | ||
322 | sort: '-name', | ||
323 | start: 0, | ||
324 | count: 5 | ||
325 | }) | ||
326 | |||
327 | const videos = res.body.data | ||
328 | expect(videos).to.have.lengthOf(2) | ||
329 | |||
330 | expect(videos[0].name).to.equal('video 2 server 2') | ||
331 | |||
332 | redundanciesToRemove = [] | ||
333 | const video = videos[0] | ||
334 | expect(video.redundancies.files).to.have.lengthOf(4) | ||
335 | expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) | ||
336 | |||
337 | const redundancies = video.redundancies.files.concat(video.redundancies.streamingPlaylists) | ||
338 | |||
339 | for (const r of redundancies) { | ||
340 | redundanciesToRemove.push(r.id) | ||
341 | } | ||
342 | } | ||
343 | }) | ||
344 | |||
345 | it('Should remove another (auto) redundancy', async function () { | ||
346 | { | ||
347 | for (const redundancyId of redundanciesToRemove) { | ||
348 | await removeVideoRedundancy({ | ||
349 | url: servers[0].url, | ||
350 | accessToken: servers[0].accessToken, | ||
351 | redundancyId | ||
352 | }) | ||
353 | } | ||
354 | |||
355 | const res = await listVideoRedundancies({ | ||
356 | url: servers[0].url, | ||
357 | accessToken: servers[0].accessToken, | ||
358 | target: 'remote-videos', | ||
359 | sort: '-name', | ||
360 | start: 0, | ||
361 | count: 5 | ||
362 | }) | ||
363 | |||
364 | const videos = res.body.data | ||
365 | expect(videos[0].name).to.equal('video 1 server 2') | ||
366 | expect(videos).to.have.lengthOf(1) | ||
367 | } | ||
368 | }) | ||
369 | |||
370 | after(async function () { | ||
371 | await cleanupTests(servers) | ||
372 | }) | ||
373 | }) | ||
diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts index 1cdf93aa1..c5037a541 100644 --- a/server/tests/api/redundancy/redundancy.ts +++ b/server/tests/api/redundancy/redundancy.ts | |||
@@ -1,11 +1,12 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { VideoDetails } from '../../../../shared/models/videos' | 5 | import { VideoDetails } from '../../../../shared/models/videos' |
6 | import { | 6 | import { |
7 | checkSegmentHash, | 7 | checkSegmentHash, |
8 | checkVideoFilesWereRemoved, cleanupTests, | 8 | checkVideoFilesWereRemoved, |
9 | cleanupTests, | ||
9 | doubleFollow, | 10 | doubleFollow, |
10 | flushAndRunMultipleServers, | 11 | flushAndRunMultipleServers, |
11 | getFollowingListPaginationAndSort, | 12 | getFollowingListPaginationAndSort, |
@@ -28,11 +29,16 @@ import { | |||
28 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 29 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
29 | 30 | ||
30 | import * as magnetUtil from 'magnet-uri' | 31 | import * as magnetUtil from 'magnet-uri' |
31 | import { updateRedundancy } from '../../../../shared/extra-utils/server/redundancy' | 32 | import { |
33 | addVideoRedundancy, | ||
34 | listVideoRedundancies, | ||
35 | removeVideoRedundancy, | ||
36 | updateRedundancy | ||
37 | } from '../../../../shared/extra-utils/server/redundancy' | ||
32 | import { ActorFollow } from '../../../../shared/models/actors' | 38 | import { ActorFollow } from '../../../../shared/models/actors' |
33 | import { readdir } from 'fs-extra' | 39 | import { readdir } from 'fs-extra' |
34 | import { join } from 'path' | 40 | import { join } from 'path' |
35 | import { VideoRedundancyStrategy } from '../../../../shared/models/redundancy' | 41 | import { VideoRedundancy, VideoRedundancyStrategy, VideoRedundancyStrategyWithManual } from '../../../../shared/models/redundancy' |
36 | import { getStats } from '../../../../shared/extra-utils/server/stats' | 42 | import { getStats } from '../../../../shared/extra-utils/server/stats' |
37 | import { ServerStats } from '../../../../shared/models/server/server-stats.model' | 43 | import { ServerStats } from '../../../../shared/models/server/server-stats.model' |
38 | 44 | ||
@@ -40,6 +46,7 @@ const expect = chai.expect | |||
40 | 46 | ||
41 | let servers: ServerInfo[] = [] | 47 | let servers: ServerInfo[] = [] |
42 | let video1Server2UUID: string | 48 | let video1Server2UUID: string |
49 | let video1Server2Id: number | ||
43 | 50 | ||
44 | function checkMagnetWebseeds (file: { magnetUri: string, resolution: { id: number } }, baseWebseeds: string[], server: ServerInfo) { | 51 | function checkMagnetWebseeds (file: { magnetUri: string, resolution: { id: number } }, baseWebseeds: string[], server: ServerInfo) { |
45 | const parsed = magnetUtil.decode(file.magnetUri) | 52 | const parsed = magnetUtil.decode(file.magnetUri) |
@@ -52,7 +59,19 @@ function checkMagnetWebseeds (file: { magnetUri: string, resolution: { id: numbe | |||
52 | expect(parsed.urlList).to.have.lengthOf(baseWebseeds.length) | 59 | expect(parsed.urlList).to.have.lengthOf(baseWebseeds.length) |
53 | } | 60 | } |
54 | 61 | ||
55 | async function flushAndRunServers (strategy: VideoRedundancyStrategy, additionalParams: any = {}) { | 62 | async function flushAndRunServers (strategy: VideoRedundancyStrategy | null, additionalParams: any = {}) { |
63 | const strategies: any[] = [] | ||
64 | |||
65 | if (strategy !== null) { | ||
66 | strategies.push( | ||
67 | immutableAssign({ | ||
68 | min_lifetime: '1 hour', | ||
69 | strategy: strategy, | ||
70 | size: '400KB' | ||
71 | }, additionalParams) | ||
72 | ) | ||
73 | } | ||
74 | |||
56 | const config = { | 75 | const config = { |
57 | transcoding: { | 76 | transcoding: { |
58 | hls: { | 77 | hls: { |
@@ -62,36 +81,32 @@ async function flushAndRunServers (strategy: VideoRedundancyStrategy, additional | |||
62 | redundancy: { | 81 | redundancy: { |
63 | videos: { | 82 | videos: { |
64 | check_interval: '5 seconds', | 83 | check_interval: '5 seconds', |
65 | strategies: [ | 84 | strategies |
66 | immutableAssign({ | ||
67 | min_lifetime: '1 hour', | ||
68 | strategy: strategy, | ||
69 | size: '400KB' | ||
70 | }, additionalParams) | ||
71 | ] | ||
72 | } | 85 | } |
73 | } | 86 | } |
74 | } | 87 | } |
88 | |||
75 | servers = await flushAndRunMultipleServers(3, config) | 89 | servers = await flushAndRunMultipleServers(3, config) |
76 | 90 | ||
77 | // Get the access tokens | 91 | // Get the access tokens |
78 | await setAccessTokensToServers(servers) | 92 | await setAccessTokensToServers(servers) |
79 | 93 | ||
80 | { | 94 | { |
81 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 server 2' }) | 95 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 server 2' }) |
82 | video1Server2UUID = res.body.video.uuid | 96 | video1Server2UUID = res.body.video.uuid |
97 | video1Server2Id = res.body.video.id | ||
83 | 98 | ||
84 | await viewVideo(servers[ 1 ].url, video1Server2UUID) | 99 | await viewVideo(servers[1].url, video1Server2UUID) |
85 | } | 100 | } |
86 | 101 | ||
87 | await waitJobs(servers) | 102 | await waitJobs(servers) |
88 | 103 | ||
89 | // Server 1 and server 2 follow each other | 104 | // Server 1 and server 2 follow each other |
90 | await doubleFollow(servers[ 0 ], servers[ 1 ]) | 105 | await doubleFollow(servers[0], servers[1]) |
91 | // Server 1 and server 3 follow each other | 106 | // Server 1 and server 3 follow each other |
92 | await doubleFollow(servers[ 0 ], servers[ 2 ]) | 107 | await doubleFollow(servers[0], servers[2]) |
93 | // Server 2 and server 3 follow each other | 108 | // Server 2 and server 3 follow each other |
94 | await doubleFollow(servers[ 1 ], servers[ 2 ]) | 109 | await doubleFollow(servers[1], servers[2]) |
95 | 110 | ||
96 | await waitJobs(servers) | 111 | await waitJobs(servers) |
97 | } | 112 | } |
@@ -100,7 +115,7 @@ async function check1WebSeed (videoUUID?: string) { | |||
100 | if (!videoUUID) videoUUID = video1Server2UUID | 115 | if (!videoUUID) videoUUID = video1Server2UUID |
101 | 116 | ||
102 | const webseeds = [ | 117 | const webseeds = [ |
103 | `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}` | 118 | `http://localhost:${servers[1].port}/static/webseed/${videoUUID}` |
104 | ] | 119 | ] |
105 | 120 | ||
106 | for (const server of servers) { | 121 | for (const server of servers) { |
@@ -118,8 +133,8 @@ async function check2Webseeds (videoUUID?: string) { | |||
118 | if (!videoUUID) videoUUID = video1Server2UUID | 133 | if (!videoUUID) videoUUID = video1Server2UUID |
119 | 134 | ||
120 | const webseeds = [ | 135 | const webseeds = [ |
121 | `http://localhost:${servers[ 0 ].port}/static/redundancy/${videoUUID}`, | 136 | `http://localhost:${servers[0].port}/static/redundancy/${videoUUID}`, |
122 | `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}` | 137 | `http://localhost:${servers[1].port}/static/webseed/${videoUUID}` |
123 | ] | 138 | ] |
124 | 139 | ||
125 | for (const server of servers) { | 140 | for (const server of servers) { |
@@ -216,41 +231,50 @@ async function check1PlaylistRedundancies (videoUUID?: string) { | |||
216 | } | 231 | } |
217 | } | 232 | } |
218 | 233 | ||
219 | async function checkStatsWith2Webseed (strategy: VideoRedundancyStrategy) { | 234 | async function checkStatsGlobal (strategy: VideoRedundancyStrategyWithManual) { |
235 | let totalSize: number = null | ||
236 | let statsLength = 1 | ||
237 | |||
238 | if (strategy !== 'manual') { | ||
239 | totalSize = 409600 | ||
240 | statsLength = 2 | ||
241 | } | ||
242 | |||
220 | const res = await getStats(servers[0].url) | 243 | const res = await getStats(servers[0].url) |
221 | const data: ServerStats = res.body | 244 | const data: ServerStats = res.body |
222 | 245 | ||
223 | expect(data.videosRedundancy).to.have.lengthOf(1) | 246 | expect(data.videosRedundancy).to.have.lengthOf(statsLength) |
224 | const stat = data.videosRedundancy[0] | ||
225 | 247 | ||
248 | const stat = data.videosRedundancy[0] | ||
226 | expect(stat.strategy).to.equal(strategy) | 249 | expect(stat.strategy).to.equal(strategy) |
227 | expect(stat.totalSize).to.equal(409600) | 250 | expect(stat.totalSize).to.equal(totalSize) |
251 | |||
252 | return stat | ||
253 | } | ||
254 | |||
255 | async function checkStatsWith2Webseed (strategy: VideoRedundancyStrategyWithManual) { | ||
256 | const stat = await checkStatsGlobal(strategy) | ||
257 | |||
228 | expect(stat.totalUsed).to.be.at.least(1).and.below(409601) | 258 | expect(stat.totalUsed).to.be.at.least(1).and.below(409601) |
229 | expect(stat.totalVideoFiles).to.equal(4) | 259 | expect(stat.totalVideoFiles).to.equal(4) |
230 | expect(stat.totalVideos).to.equal(1) | 260 | expect(stat.totalVideos).to.equal(1) |
231 | } | 261 | } |
232 | 262 | ||
233 | async function checkStatsWith1Webseed (strategy: VideoRedundancyStrategy) { | 263 | async function checkStatsWith1Webseed (strategy: VideoRedundancyStrategyWithManual) { |
234 | const res = await getStats(servers[0].url) | 264 | const stat = await checkStatsGlobal(strategy) |
235 | const data: ServerStats = res.body | ||
236 | 265 | ||
237 | expect(data.videosRedundancy).to.have.lengthOf(1) | ||
238 | |||
239 | const stat = data.videosRedundancy[0] | ||
240 | expect(stat.strategy).to.equal(strategy) | ||
241 | expect(stat.totalSize).to.equal(409600) | ||
242 | expect(stat.totalUsed).to.equal(0) | 266 | expect(stat.totalUsed).to.equal(0) |
243 | expect(stat.totalVideoFiles).to.equal(0) | 267 | expect(stat.totalVideoFiles).to.equal(0) |
244 | expect(stat.totalVideos).to.equal(0) | 268 | expect(stat.totalVideos).to.equal(0) |
245 | } | 269 | } |
246 | 270 | ||
247 | async function enableRedundancyOnServer1 () { | 271 | async function enableRedundancyOnServer1 () { |
248 | await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, true) | 272 | await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, true) |
249 | 273 | ||
250 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: '-createdAt' }) | 274 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: '-createdAt' }) |
251 | const follows: ActorFollow[] = res.body.data | 275 | const follows: ActorFollow[] = res.body.data |
252 | const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`) | 276 | const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`) |
253 | const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`) | 277 | const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`) |
254 | 278 | ||
255 | expect(server3).to.not.be.undefined | 279 | expect(server3).to.not.be.undefined |
256 | expect(server3.following.hostRedundancyAllowed).to.be.false | 280 | expect(server3.following.hostRedundancyAllowed).to.be.false |
@@ -260,12 +284,12 @@ async function enableRedundancyOnServer1 () { | |||
260 | } | 284 | } |
261 | 285 | ||
262 | async function disableRedundancyOnServer1 () { | 286 | async function disableRedundancyOnServer1 () { |
263 | await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, false) | 287 | await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, false) |
264 | 288 | ||
265 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: '-createdAt' }) | 289 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: '-createdAt' }) |
266 | const follows: ActorFollow[] = res.body.data | 290 | const follows: ActorFollow[] = res.body.data |
267 | const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`) | 291 | const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`) |
268 | const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`) | 292 | const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`) |
269 | 293 | ||
270 | expect(server3).to.not.be.undefined | 294 | expect(server3).to.not.be.undefined |
271 | expect(server3.following.hostRedundancyAllowed).to.be.false | 295 | expect(server3.following.hostRedundancyAllowed).to.be.false |
@@ -410,8 +434,8 @@ describe('Test videos redundancy', function () { | |||
410 | it('Should view 2 times the first video to have > min_views config', async function () { | 434 | it('Should view 2 times the first video to have > min_views config', async function () { |
411 | this.timeout(80000) | 435 | this.timeout(80000) |
412 | 436 | ||
413 | await viewVideo(servers[ 0 ].url, video1Server2UUID) | 437 | await viewVideo(servers[0].url, video1Server2UUID) |
414 | await viewVideo(servers[ 2 ].url, video1Server2UUID) | 438 | await viewVideo(servers[2].url, video1Server2UUID) |
415 | 439 | ||
416 | await wait(10000) | 440 | await wait(10000) |
417 | await waitJobs(servers) | 441 | await waitJobs(servers) |
@@ -446,6 +470,74 @@ describe('Test videos redundancy', function () { | |||
446 | }) | 470 | }) |
447 | }) | 471 | }) |
448 | 472 | ||
473 | describe('With manual strategy', function () { | ||
474 | before(function () { | ||
475 | this.timeout(120000) | ||
476 | |||
477 | return flushAndRunServers(null) | ||
478 | }) | ||
479 | |||
480 | it('Should have 1 webseed on the first video', async function () { | ||
481 | await check1WebSeed() | ||
482 | await check0PlaylistRedundancies() | ||
483 | await checkStatsWith1Webseed('manual') | ||
484 | }) | ||
485 | |||
486 | it('Should create a redundancy on first video', async function () { | ||
487 | await addVideoRedundancy({ | ||
488 | url: servers[0].url, | ||
489 | accessToken: servers[0].accessToken, | ||
490 | videoId: video1Server2Id | ||
491 | }) | ||
492 | }) | ||
493 | |||
494 | it('Should have 2 webseeds on the first video', async function () { | ||
495 | this.timeout(80000) | ||
496 | |||
497 | await waitJobs(servers) | ||
498 | await waitUntilLog(servers[0], 'Duplicated ', 5) | ||
499 | await waitJobs(servers) | ||
500 | |||
501 | await check2Webseeds() | ||
502 | await check1PlaylistRedundancies() | ||
503 | await checkStatsWith2Webseed('manual') | ||
504 | }) | ||
505 | |||
506 | it('Should manually remove redundancies on server 1 and remove duplicated videos', async function () { | ||
507 | this.timeout(80000) | ||
508 | |||
509 | const res = await listVideoRedundancies({ | ||
510 | url: servers[0].url, | ||
511 | accessToken: servers[0].accessToken, | ||
512 | target: 'remote-videos' | ||
513 | }) | ||
514 | |||
515 | const videos = res.body.data as VideoRedundancy[] | ||
516 | expect(videos).to.have.lengthOf(1) | ||
517 | |||
518 | const video = videos[0] | ||
519 | for (const r of video.redundancies.files.concat(video.redundancies.streamingPlaylists)) { | ||
520 | await removeVideoRedundancy({ | ||
521 | url: servers[0].url, | ||
522 | accessToken: servers[0].accessToken, | ||
523 | redundancyId: r.id | ||
524 | }) | ||
525 | } | ||
526 | |||
527 | await waitJobs(servers) | ||
528 | await wait(5000) | ||
529 | |||
530 | await check1WebSeed() | ||
531 | await check0PlaylistRedundancies() | ||
532 | |||
533 | await checkVideoFilesWereRemoved(video1Server2UUID, servers[0].serverNumber, [ 'videos' ]) | ||
534 | }) | ||
535 | |||
536 | after(async function () { | ||
537 | await cleanupTests(servers) | ||
538 | }) | ||
539 | }) | ||
540 | |||
449 | describe('Test expiration', function () { | 541 | describe('Test expiration', function () { |
450 | const strategy = 'recently-added' | 542 | const strategy = 'recently-added' |
451 | 543 | ||
@@ -528,7 +620,7 @@ describe('Test videos redundancy', function () { | |||
528 | await check1PlaylistRedundancies() | 620 | await check1PlaylistRedundancies() |
529 | await checkStatsWith2Webseed(strategy) | 621 | await checkStatsWith2Webseed(strategy) |
530 | 622 | ||
531 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 2 server 2' }) | 623 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 2 server 2' }) |
532 | video2Server2UUID = res.body.video.uuid | 624 | video2Server2UUID = res.body.video.uuid |
533 | }) | 625 | }) |
534 | 626 | ||
@@ -560,8 +652,8 @@ describe('Test videos redundancy', function () { | |||
560 | 652 | ||
561 | await waitJobs(servers) | 653 | await waitJobs(servers) |
562 | 654 | ||
563 | killallServers([ servers[ 0 ] ]) | 655 | killallServers([ servers[0] ]) |
564 | await reRunServer(servers[ 0 ], { | 656 | await reRunServer(servers[0], { |
565 | redundancy: { | 657 | redundancy: { |
566 | videos: { | 658 | videos: { |
567 | check_interval: '1 second', | 659 | check_interval: '1 second', |
diff --git a/server/tests/api/search/search-activitypub-video-channels.ts b/server/tests/api/search/search-activitypub-video-channels.ts index d5f0a5457..d7e3ed5be 100644 --- a/server/tests/api/search/search-activitypub-video-channels.ts +++ b/server/tests/api/search/search-activitypub-video-channels.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -39,7 +39,7 @@ describe('Test ActivityPub video channels search', function () { | |||
39 | await setAccessTokensToServers(servers) | 39 | await setAccessTokensToServers(servers) |
40 | 40 | ||
41 | { | 41 | { |
42 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: 'user1_server1', password: 'password' }) | 42 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: 'user1_server1', password: 'password' }) |
43 | const channel = { | 43 | const channel = { |
44 | name: 'channel1_server1', | 44 | name: 'channel1_server1', |
45 | displayName: 'Channel 1 server 1' | 45 | displayName: 'Channel 1 server 1' |
@@ -49,7 +49,7 @@ describe('Test ActivityPub video channels search', function () { | |||
49 | 49 | ||
50 | { | 50 | { |
51 | const user = { username: 'user1_server2', password: 'password' } | 51 | const user = { username: 'user1_server2', password: 'password' } |
52 | await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password }) | 52 | await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password }) |
53 | userServer2Token = await userLogin(servers[1], user) | 53 | userServer2Token = await userLogin(servers[1], user) |
54 | 54 | ||
55 | const channel = { | 55 | const channel = { |
@@ -70,8 +70,8 @@ describe('Test ActivityPub video channels search', function () { | |||
70 | this.timeout(15000) | 70 | this.timeout(15000) |
71 | 71 | ||
72 | { | 72 | { |
73 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server3' | 73 | const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server3' |
74 | const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken) | 74 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
75 | 75 | ||
76 | expect(res.body.total).to.equal(0) | 76 | expect(res.body.total).to.equal(0) |
77 | expect(res.body.data).to.be.an('array') | 77 | expect(res.body.data).to.be.an('array') |
@@ -80,7 +80,7 @@ describe('Test ActivityPub video channels search', function () { | |||
80 | 80 | ||
81 | { | 81 | { |
82 | // Without token | 82 | // Without token |
83 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' | 83 | const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2' |
84 | const res = await searchVideoChannel(servers[0].url, search) | 84 | const res = await searchVideoChannel(servers[0].url, search) |
85 | 85 | ||
86 | expect(res.body.total).to.equal(0) | 86 | expect(res.body.total).to.equal(0) |
@@ -91,35 +91,35 @@ describe('Test ActivityPub video channels search', function () { | |||
91 | 91 | ||
92 | it('Should search a local video channel', async function () { | 92 | it('Should search a local video channel', async function () { |
93 | const searches = [ | 93 | const searches = [ |
94 | 'http://localhost:' + servers[ 0 ].port + '/video-channels/channel1_server1', | 94 | 'http://localhost:' + servers[0].port + '/video-channels/channel1_server1', |
95 | 'channel1_server1@localhost:' + servers[ 0 ].port | 95 | 'channel1_server1@localhost:' + servers[0].port |
96 | ] | 96 | ] |
97 | 97 | ||
98 | for (const search of searches) { | 98 | for (const search of searches) { |
99 | const res = await searchVideoChannel(servers[ 0 ].url, search) | 99 | const res = await searchVideoChannel(servers[0].url, search) |
100 | 100 | ||
101 | expect(res.body.total).to.equal(1) | 101 | expect(res.body.total).to.equal(1) |
102 | expect(res.body.data).to.be.an('array') | 102 | expect(res.body.data).to.be.an('array') |
103 | expect(res.body.data).to.have.lengthOf(1) | 103 | expect(res.body.data).to.have.lengthOf(1) |
104 | expect(res.body.data[ 0 ].name).to.equal('channel1_server1') | 104 | expect(res.body.data[0].name).to.equal('channel1_server1') |
105 | expect(res.body.data[ 0 ].displayName).to.equal('Channel 1 server 1') | 105 | expect(res.body.data[0].displayName).to.equal('Channel 1 server 1') |
106 | } | 106 | } |
107 | }) | 107 | }) |
108 | 108 | ||
109 | it('Should search a remote video channel with URL or handle', async function () { | 109 | it('Should search a remote video channel with URL or handle', async function () { |
110 | const searches = [ | 110 | const searches = [ |
111 | 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2', | 111 | 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2', |
112 | 'channel1_server2@localhost:' + servers[ 1 ].port | 112 | 'channel1_server2@localhost:' + servers[1].port |
113 | ] | 113 | ] |
114 | 114 | ||
115 | for (const search of searches) { | 115 | for (const search of searches) { |
116 | const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken) | 116 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
117 | 117 | ||
118 | expect(res.body.total).to.equal(1) | 118 | expect(res.body.total).to.equal(1) |
119 | expect(res.body.data).to.be.an('array') | 119 | expect(res.body.data).to.be.an('array') |
120 | expect(res.body.data).to.have.lengthOf(1) | 120 | expect(res.body.data).to.have.lengthOf(1) |
121 | expect(res.body.data[ 0 ].name).to.equal('channel1_server2') | 121 | expect(res.body.data[0].name).to.equal('channel1_server2') |
122 | expect(res.body.data[ 0 ].displayName).to.equal('Channel 1 server 2') | 122 | expect(res.body.data[0].displayName).to.equal('Channel 1 server 2') |
123 | } | 123 | } |
124 | }) | 124 | }) |
125 | 125 | ||
@@ -137,13 +137,13 @@ describe('Test ActivityPub video channels search', function () { | |||
137 | 137 | ||
138 | await waitJobs(servers) | 138 | await waitJobs(servers) |
139 | 139 | ||
140 | const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5) | 140 | const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:' + servers[1].port, 0, 5) |
141 | expect(res.body.total).to.equal(0) | 141 | expect(res.body.total).to.equal(0) |
142 | expect(res.body.data).to.have.lengthOf(0) | 142 | expect(res.body.data).to.have.lengthOf(0) |
143 | }) | 143 | }) |
144 | 144 | ||
145 | it('Should list video channel videos of server 2 with token', async function () { | 145 | it('Should list video channel videos of server 2 with token', async function () { |
146 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5) | 146 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:' + servers[1].port, 0, 5) |
147 | 147 | ||
148 | expect(res.body.total).to.equal(1) | 148 | expect(res.body.total).to.equal(1) |
149 | expect(res.body.data[0].name).to.equal('video 1 server 2') | 149 | expect(res.body.data[0].name).to.equal('video 1 server 2') |
@@ -159,7 +159,7 @@ describe('Test ActivityPub video channels search', function () { | |||
159 | // Expire video channel | 159 | // Expire video channel |
160 | await wait(10000) | 160 | await wait(10000) |
161 | 161 | ||
162 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' | 162 | const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2' |
163 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) | 163 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
164 | expect(res.body.total).to.equal(1) | 164 | expect(res.body.total).to.equal(1) |
165 | expect(res.body.data).to.have.lengthOf(1) | 165 | expect(res.body.data).to.have.lengthOf(1) |
@@ -182,12 +182,12 @@ describe('Test ActivityPub video channels search', function () { | |||
182 | // Expire video channel | 182 | // Expire video channel |
183 | await wait(10000) | 183 | await wait(10000) |
184 | 184 | ||
185 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' | 185 | const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2' |
186 | await searchVideoChannel(servers[0].url, search, servers[0].accessToken) | 186 | await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
187 | 187 | ||
188 | await waitJobs(servers) | 188 | await waitJobs(servers) |
189 | 189 | ||
190 | const videoChannelName = 'channel1_server2@localhost:' + servers[ 1 ].port | 190 | const videoChannelName = 'channel1_server2@localhost:' + servers[1].port |
191 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, videoChannelName, 0, 5, '-createdAt') | 191 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, videoChannelName, 0, 5, '-createdAt') |
192 | 192 | ||
193 | expect(res.body.total).to.equal(2) | 193 | expect(res.body.total).to.equal(2) |
@@ -204,7 +204,7 @@ describe('Test ActivityPub video channels search', function () { | |||
204 | // Expire video | 204 | // Expire video |
205 | await wait(10000) | 205 | await wait(10000) |
206 | 206 | ||
207 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' | 207 | const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2' |
208 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) | 208 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
209 | expect(res.body.total).to.equal(0) | 209 | expect(res.body.total).to.equal(0) |
210 | expect(res.body.data).to.have.lengthOf(0) | 210 | expect(res.body.data).to.have.lengthOf(0) |
diff --git a/server/tests/api/search/search-activitypub-videos.ts b/server/tests/api/search/search-activitypub-videos.ts index dbfefadda..c62dfca0d 100644 --- a/server/tests/api/search/search-activitypub-videos.ts +++ b/server/tests/api/search/search-activitypub-videos.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -34,12 +34,12 @@ describe('Test ActivityPub videos search', function () { | |||
34 | await setAccessTokensToServers(servers) | 34 | await setAccessTokensToServers(servers) |
35 | 35 | ||
36 | { | 36 | { |
37 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1 on server 1' }) | 37 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 1 on server 1' }) |
38 | videoServer1UUID = res.body.video.uuid | 38 | videoServer1UUID = res.body.video.uuid |
39 | } | 39 | } |
40 | 40 | ||
41 | { | 41 | { |
42 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 on server 2' }) | 42 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 on server 2' }) |
43 | videoServer2UUID = res.body.video.uuid | 43 | videoServer2UUID = res.body.video.uuid |
44 | } | 44 | } |
45 | 45 | ||
@@ -49,7 +49,7 @@ describe('Test ActivityPub videos search', function () { | |||
49 | it('Should not find a remote video', async function () { | 49 | it('Should not find a remote video', async function () { |
50 | { | 50 | { |
51 | const search = 'http://localhost:' + servers[1].port + '/videos/watch/43' | 51 | const search = 'http://localhost:' + servers[1].port + '/videos/watch/43' |
52 | const res = await searchVideoWithToken(servers[ 0 ].url, search, servers[ 0 ].accessToken) | 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') |
diff --git a/server/tests/api/search/search-videos.ts b/server/tests/api/search/search-videos.ts index 7882d9373..4801fe04a 100644 --- a/server/tests/api/search/search-videos.ts +++ b/server/tests/api/search/search-videos.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -78,7 +78,7 @@ describe('Test videos search', function () { | |||
78 | const attributes5 = immutableAssign(attributes1, { name: attributes1.name + ' - 5', licence: 2, language: undefined }) | 78 | const attributes5 = immutableAssign(attributes1, { name: attributes1.name + ' - 5', licence: 2, language: undefined }) |
79 | await uploadVideo(server.url, server.accessToken, attributes5) | 79 | await uploadVideo(server.url, server.accessToken, attributes5) |
80 | 80 | ||
81 | const attributes6 = immutableAssign(attributes1, { name: attributes1.name + ' - 6', tags: [ 't1', 't2 '] }) | 81 | const attributes6 = immutableAssign(attributes1, { name: attributes1.name + ' - 6', tags: [ 't1', 't2' ] }) |
82 | await uploadVideo(server.url, server.accessToken, attributes6) | 82 | await uploadVideo(server.url, server.accessToken, attributes6) |
83 | 83 | ||
84 | const attributes7 = immutableAssign(attributes1, { | 84 | const attributes7 = immutableAssign(attributes1, { |
@@ -269,16 +269,16 @@ describe('Test videos search', function () { | |||
269 | { | 269 | { |
270 | const res = await advancedVideosSearch(server.url, query) | 270 | const res = await advancedVideosSearch(server.url, query) |
271 | expect(res.body.total).to.equal(2) | 271 | expect(res.body.total).to.equal(2) |
272 | expect(res.body.data[ 0 ].name).to.equal('1111 2222 3333 - 3') | 272 | expect(res.body.data[0].name).to.equal('1111 2222 3333 - 3') |
273 | expect(res.body.data[ 1 ].name).to.equal('1111 2222 3333 - 4') | 273 | expect(res.body.data[1].name).to.equal('1111 2222 3333 - 4') |
274 | } | 274 | } |
275 | 275 | ||
276 | { | 276 | { |
277 | const res = await advancedVideosSearch(server.url, immutableAssign(query, { languageOneOf: [ 'pl', 'en', '_unknown' ] })) | 277 | const res = await advancedVideosSearch(server.url, immutableAssign(query, { languageOneOf: [ 'pl', 'en', '_unknown' ] })) |
278 | expect(res.body.total).to.equal(3) | 278 | expect(res.body.total).to.equal(3) |
279 | expect(res.body.data[ 0 ].name).to.equal('1111 2222 3333 - 3') | 279 | expect(res.body.data[0].name).to.equal('1111 2222 3333 - 3') |
280 | expect(res.body.data[ 1 ].name).to.equal('1111 2222 3333 - 4') | 280 | expect(res.body.data[1].name).to.equal('1111 2222 3333 - 4') |
281 | expect(res.body.data[ 2 ].name).to.equal('1111 2222 3333 - 5') | 281 | expect(res.body.data[2].name).to.equal('1111 2222 3333 - 5') |
282 | } | 282 | } |
283 | 283 | ||
284 | { | 284 | { |
diff --git a/server/tests/api/server/auto-follows.ts b/server/tests/api/server/auto-follows.ts index a06f578fc..5f48dc0eb 100644 --- a/server/tests/api/server/auto-follows.ts +++ b/server/tests/api/server/auto-follows.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -59,9 +59,10 @@ async function server1Follows2 (servers: ServerInfo[]) { | |||
59 | 59 | ||
60 | async function resetFollows (servers: ServerInfo[]) { | 60 | async function resetFollows (servers: ServerInfo[]) { |
61 | try { | 61 | try { |
62 | await unfollow(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ]) | 62 | await unfollow(servers[0].url, servers[0].accessToken, servers[1]) |
63 | await unfollow(servers[ 1 ].url, servers[ 1 ].accessToken, servers[ 0 ]) | 63 | await unfollow(servers[1].url, servers[1].accessToken, servers[0]) |
64 | } catch { /* empty */ } | 64 | } catch { /* empty */ |
65 | } | ||
65 | 66 | ||
66 | await waitJobs(servers) | 67 | await waitJobs(servers) |
67 | 68 | ||
@@ -163,8 +164,8 @@ describe('Test auto follows', function () { | |||
163 | await wait(5000) | 164 | await wait(5000) |
164 | await waitJobs(servers) | 165 | await waitJobs(servers) |
165 | 166 | ||
166 | await checkFollow(servers[ 0 ], servers[ 1 ], false) | 167 | await checkFollow(servers[0], servers[1], false) |
167 | await checkFollow(servers[ 1 ], servers[ 0 ], false) | 168 | await checkFollow(servers[1], servers[0], false) |
168 | }) | 169 | }) |
169 | 170 | ||
170 | it('Should auto follow the index', async function () { | 171 | it('Should auto follow the index', async function () { |
@@ -187,7 +188,7 @@ describe('Test auto follows', function () { | |||
187 | await wait(5000) | 188 | await wait(5000) |
188 | await waitJobs(servers) | 189 | await waitJobs(servers) |
189 | 190 | ||
190 | await checkFollow(servers[ 0 ], servers[ 1 ], true) | 191 | await checkFollow(servers[0], servers[1], true) |
191 | 192 | ||
192 | await resetFollows(servers) | 193 | await resetFollows(servers) |
193 | }) | 194 | }) |
@@ -200,8 +201,8 @@ describe('Test auto follows', function () { | |||
200 | await wait(5000) | 201 | await wait(5000) |
201 | await waitJobs(servers) | 202 | await waitJobs(servers) |
202 | 203 | ||
203 | await checkFollow(servers[ 0 ], servers[ 1 ], false) | 204 | await checkFollow(servers[0], servers[1], false) |
204 | await checkFollow(servers[ 0 ], servers[ 2 ], true) | 205 | await checkFollow(servers[0], servers[2], true) |
205 | }) | 206 | }) |
206 | }) | 207 | }) |
207 | 208 | ||
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index cf99e5c0a..642525455 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -11,11 +11,14 @@ import { | |||
11 | getAbout, | 11 | getAbout, |
12 | getConfig, | 12 | getConfig, |
13 | getCustomConfig, | 13 | getCustomConfig, |
14 | killallServers, parallelTests, | 14 | killallServers, |
15 | parallelTests, | ||
15 | registerUser, | 16 | registerUser, |
16 | reRunServer, ServerInfo, | 17 | reRunServer, |
18 | ServerInfo, | ||
17 | setAccessTokensToServers, | 19 | setAccessTokensToServers, |
18 | updateCustomConfig, uploadVideo | 20 | updateCustomConfig, |
21 | uploadVideo | ||
19 | } from '../../../../shared/extra-utils' | 22 | } from '../../../../shared/extra-utils' |
20 | import { ServerConfig } from '../../../../shared/models' | 23 | import { ServerConfig } from '../../../../shared/models' |
21 | 24 | ||
diff --git a/server/tests/api/server/contact-form.ts b/server/tests/api/server/contact-form.ts index e4e895acb..bd1b0e38a 100644 --- a/server/tests/api/server/contact-form.ts +++ b/server/tests/api/server/contact-form.ts | |||
@@ -1,16 +1,8 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { cleanupTests, flushAndRunServer, ServerInfo, setAccessTokensToServers, wait } from '../../../../shared/extra-utils' |
6 | flushTests, | ||
7 | killallServers, | ||
8 | flushAndRunServer, | ||
9 | ServerInfo, | ||
10 | setAccessTokensToServers, | ||
11 | wait, | ||
12 | cleanupTests | ||
13 | } from '../../../../shared/extra-utils' | ||
14 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' | 6 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' |
15 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 7 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
16 | import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' | 8 | import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' |
diff --git a/server/tests/api/server/email.ts b/server/tests/api/server/email.ts index c55a221f2..f18859e5d 100644 --- a/server/tests/api/server/email.ts +++ b/server/tests/api/server/email.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts index 46663bf7c..a73440286 100644 --- a/server/tests/api/server/follow-constraints.ts +++ b/server/tests/api/server/follow-constraints.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -35,11 +35,11 @@ describe('Test follow constraints', function () { | |||
35 | await setAccessTokensToServers(servers) | 35 | await setAccessTokensToServers(servers) |
36 | 36 | ||
37 | { | 37 | { |
38 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video server 1' }) | 38 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video server 1' }) |
39 | video1UUID = res.body.video.uuid | 39 | video1UUID = res.body.video.uuid |
40 | } | 40 | } |
41 | { | 41 | { |
42 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video server 2' }) | 42 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video server 2' }) |
43 | video2UUID = res.body.video.uuid | 43 | video2UUID = res.body.video.uuid |
44 | } | 44 | } |
45 | 45 | ||
@@ -47,7 +47,7 @@ describe('Test follow constraints', function () { | |||
47 | username: 'user1', | 47 | username: 'user1', |
48 | password: 'super_password' | 48 | password: 'super_password' |
49 | } | 49 | } |
50 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 50 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
51 | userAccessToken = await userLogin(servers[0], user) | 51 | userAccessToken = await userLogin(servers[0], user) |
52 | 52 | ||
53 | await doubleFollow(servers[0], servers[1]) | 53 | await doubleFollow(servers[0], servers[1]) |
diff --git a/server/tests/api/server/follows-moderation.ts b/server/tests/api/server/follows-moderation.ts index 1984c9eb1..cee85cc4b 100644 --- a/server/tests/api/server/follows-moderation.ts +++ b/server/tests/api/server/follows-moderation.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -24,7 +24,7 @@ const expect = chai.expect | |||
24 | 24 | ||
25 | async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'accepted') { | 25 | async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'accepted') { |
26 | { | 26 | { |
27 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) | 27 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) |
28 | expect(res.body.total).to.equal(1) | 28 | expect(res.body.total).to.equal(1) |
29 | 29 | ||
30 | const follow = res.body.data[0] as ActorFollow | 30 | const follow = res.body.data[0] as ActorFollow |
@@ -34,7 +34,7 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc | |||
34 | } | 34 | } |
35 | 35 | ||
36 | { | 36 | { |
37 | const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' }) | 37 | const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' }) |
38 | expect(res.body.total).to.equal(1) | 38 | expect(res.body.total).to.equal(1) |
39 | 39 | ||
40 | const follow = res.body.data[0] as ActorFollow | 40 | const follow = res.body.data[0] as ActorFollow |
@@ -46,12 +46,12 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc | |||
46 | 46 | ||
47 | async function checkNoFollowers (servers: ServerInfo[]) { | 47 | async function checkNoFollowers (servers: ServerInfo[]) { |
48 | { | 48 | { |
49 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) | 49 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) |
50 | expect(res.body.total).to.equal(0) | 50 | expect(res.body.total).to.equal(0) |
51 | } | 51 | } |
52 | 52 | ||
53 | { | 53 | { |
54 | const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' }) | 54 | const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' }) |
55 | expect(res.body.total).to.equal(0) | 55 | expect(res.body.total).to.equal(0) |
56 | } | 56 | } |
57 | } | 57 | } |
@@ -164,17 +164,17 @@ describe('Test follows moderation', function () { | |||
164 | await waitJobs(servers) | 164 | await waitJobs(servers) |
165 | 165 | ||
166 | { | 166 | { |
167 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) | 167 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) |
168 | expect(res.body.total).to.equal(2) | 168 | expect(res.body.total).to.equal(2) |
169 | } | 169 | } |
170 | 170 | ||
171 | { | 171 | { |
172 | const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' }) | 172 | const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' }) |
173 | expect(res.body.total).to.equal(1) | 173 | expect(res.body.total).to.equal(1) |
174 | } | 174 | } |
175 | 175 | ||
176 | { | 176 | { |
177 | const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 5, sort: 'createdAt' }) | 177 | const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 5, sort: 'createdAt' }) |
178 | expect(res.body.total).to.equal(1) | 178 | expect(res.body.total).to.equal(1) |
179 | } | 179 | } |
180 | 180 | ||
@@ -184,7 +184,7 @@ describe('Test follows moderation', function () { | |||
184 | await checkServer1And2HasFollowers(servers) | 184 | await checkServer1And2HasFollowers(servers) |
185 | 185 | ||
186 | { | 186 | { |
187 | const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 5, sort: 'createdAt' }) | 187 | const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 5, sort: 'createdAt' }) |
188 | expect(res.body.total).to.equal(0) | 188 | expect(res.body.total).to.equal(0) |
189 | } | 189 | } |
190 | }) | 190 | }) |
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts index 4ffa9e791..b686af4e4 100644 --- a/server/tests/api/server/follows.ts +++ b/server/tests/api/server/follows.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -78,14 +78,14 @@ describe('Test follows', function () { | |||
78 | }) | 78 | }) |
79 | 79 | ||
80 | it('Should have 2 followings on server 1', async function () { | 80 | it('Should have 2 followings on server 1', async function () { |
81 | let res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 1, sort: 'createdAt' }) | 81 | let res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 1, sort: 'createdAt' }) |
82 | let follows = res.body.data | 82 | let follows = res.body.data |
83 | 83 | ||
84 | expect(res.body.total).to.equal(2) | 84 | expect(res.body.total).to.equal(2) |
85 | expect(follows).to.be.an('array') | 85 | expect(follows).to.be.an('array') |
86 | expect(follows.length).to.equal(1) | 86 | expect(follows.length).to.equal(1) |
87 | 87 | ||
88 | res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 1, count: 1, sort: 'createdAt' }) | 88 | res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 1, count: 1, sort: 'createdAt' }) |
89 | follows = follows.concat(res.body.data) | 89 | follows = follows.concat(res.body.data) |
90 | 90 | ||
91 | const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port) | 91 | const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port) |
@@ -101,7 +101,7 @@ describe('Test follows', function () { | |||
101 | const sort = 'createdAt' | 101 | const sort = 'createdAt' |
102 | const start = 0 | 102 | const start = 0 |
103 | const count = 1 | 103 | const count = 1 |
104 | const url = servers[ 0 ].url | 104 | const url = servers[0].url |
105 | 105 | ||
106 | { | 106 | { |
107 | const search = ':' + servers[1].port | 107 | const search = ':' + servers[1].port |
@@ -112,7 +112,7 @@ describe('Test follows', function () { | |||
112 | 112 | ||
113 | expect(res.body.total).to.equal(1) | 113 | expect(res.body.total).to.equal(1) |
114 | expect(follows.length).to.equal(1) | 114 | expect(follows.length).to.equal(1) |
115 | expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[ 1 ].port) | 115 | expect(follows[0].following.host).to.equal('localhost:' + servers[1].port) |
116 | } | 116 | } |
117 | 117 | ||
118 | { | 118 | { |
@@ -170,9 +170,9 @@ describe('Test follows', function () { | |||
170 | 170 | ||
171 | it('Should have 1 followers on server 2 and 3', async function () { | 171 | it('Should have 1 followers on server 2 and 3', async function () { |
172 | for (const server of [ servers[1], servers[2] ]) { | 172 | for (const server of [ servers[1], servers[2] ]) { |
173 | let res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 1, sort: 'createdAt' }) | 173 | const res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 1, sort: 'createdAt' }) |
174 | 174 | ||
175 | let follows = res.body.data | 175 | const follows = res.body.data |
176 | expect(res.body.total).to.equal(1) | 176 | expect(res.body.total).to.equal(1) |
177 | expect(follows).to.be.an('array') | 177 | expect(follows).to.be.an('array') |
178 | expect(follows.length).to.equal(1) | 178 | expect(follows.length).to.equal(1) |
@@ -181,7 +181,7 @@ describe('Test follows', function () { | |||
181 | }) | 181 | }) |
182 | 182 | ||
183 | it('Should search/filter followers on server 2', async function () { | 183 | it('Should search/filter followers on server 2', async function () { |
184 | const url = servers[ 2 ].url | 184 | const url = servers[2].url |
185 | const start = 0 | 185 | const start = 0 |
186 | const count = 5 | 186 | const count = 5 |
187 | const sort = 'createdAt' | 187 | const sort = 'createdAt' |
@@ -195,7 +195,7 @@ describe('Test follows', function () { | |||
195 | 195 | ||
196 | expect(res.body.total).to.equal(1) | 196 | expect(res.body.total).to.equal(1) |
197 | expect(follows.length).to.equal(1) | 197 | expect(follows.length).to.equal(1) |
198 | expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[ 2 ].port) | 198 | expect(follows[0].following.host).to.equal('localhost:' + servers[2].port) |
199 | } | 199 | } |
200 | 200 | ||
201 | { | 201 | { |
@@ -241,7 +241,7 @@ describe('Test follows', function () { | |||
241 | }) | 241 | }) |
242 | 242 | ||
243 | it('Should have 0 followers on server 1', async function () { | 243 | it('Should have 0 followers on server 1', async function () { |
244 | const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) | 244 | const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) |
245 | const follows = res.body.data | 245 | const follows = res.body.data |
246 | 246 | ||
247 | expect(res.body.total).to.equal(0) | 247 | expect(res.body.total).to.equal(0) |
@@ -271,8 +271,8 @@ describe('Test follows', function () { | |||
271 | }) | 271 | }) |
272 | 272 | ||
273 | it('Should not follow server 3 on server 1 anymore', async function () { | 273 | it('Should not follow server 3 on server 1 anymore', async function () { |
274 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' }) | 274 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' }) |
275 | let follows = res.body.data | 275 | const follows = res.body.data |
276 | 276 | ||
277 | expect(res.body.total).to.equal(1) | 277 | expect(res.body.total).to.equal(1) |
278 | expect(follows).to.be.an('array') | 278 | expect(follows).to.be.an('array') |
@@ -282,9 +282,9 @@ describe('Test follows', function () { | |||
282 | }) | 282 | }) |
283 | 283 | ||
284 | it('Should not have server 1 as follower on server 3 anymore', async function () { | 284 | it('Should not have server 1 as follower on server 3 anymore', async function () { |
285 | const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 1, sort: 'createdAt' }) | 285 | const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 1, sort: 'createdAt' }) |
286 | 286 | ||
287 | let follows = res.body.data | 287 | const follows = res.body.data |
288 | expect(res.body.total).to.equal(0) | 288 | expect(res.body.total).to.equal(0) |
289 | expect(follows).to.be.an('array') | 289 | expect(follows).to.be.an('array') |
290 | expect(follows.length).to.equal(0) | 290 | expect(follows.length).to.equal(0) |
@@ -336,59 +336,59 @@ describe('Test follows', function () { | |||
336 | tags: [ 'tag1', 'tag2', 'tag3' ] | 336 | tags: [ 'tag1', 'tag2', 'tag3' ] |
337 | } | 337 | } |
338 | 338 | ||
339 | await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-2' }) | 339 | await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-2' }) |
340 | await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-3' }) | 340 | await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-3' }) |
341 | await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, video4Attributes) | 341 | await uploadVideo(servers[2].url, servers[2].accessToken, video4Attributes) |
342 | await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-5' }) | 342 | await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-5' }) |
343 | await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-6' }) | 343 | await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-6' }) |
344 | 344 | ||
345 | { | 345 | { |
346 | const user = { username: 'captain', password: 'password' } | 346 | const user = { username: 'captain', password: 'password' } |
347 | await createUser({ url: servers[ 2 ].url, accessToken: servers[ 2 ].accessToken, username: user.username, password: user.password }) | 347 | await createUser({ url: servers[2].url, accessToken: servers[2].accessToken, username: user.username, password: user.password }) |
348 | const userAccessToken = await userLogin(servers[ 2 ], user) | 348 | const userAccessToken = await userLogin(servers[2], user) |
349 | 349 | ||
350 | const resVideos = await getVideosList(servers[ 2 ].url) | 350 | const resVideos = await getVideosList(servers[2].url) |
351 | video4 = resVideos.body.data.find(v => v.name === 'server3-4') | 351 | video4 = resVideos.body.data.find(v => v.name === 'server3-4') |
352 | 352 | ||
353 | { | 353 | { |
354 | await rateVideo(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, 'like') | 354 | await rateVideo(servers[2].url, servers[2].accessToken, video4.id, 'like') |
355 | await rateVideo(servers[ 2 ].url, userAccessToken, video4.id, 'dislike') | 355 | await rateVideo(servers[2].url, userAccessToken, video4.id, 'dislike') |
356 | } | 356 | } |
357 | 357 | ||
358 | { | 358 | { |
359 | { | 359 | { |
360 | const text = 'my super first comment' | 360 | const text = 'my super first comment' |
361 | const res = await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, text) | 361 | const res = await addVideoCommentThread(servers[2].url, servers[2].accessToken, video4.id, text) |
362 | const threadId = res.body.comment.id | 362 | const threadId = res.body.comment.id |
363 | 363 | ||
364 | const text1 = 'my super answer to thread 1' | 364 | const text1 = 'my super answer to thread 1' |
365 | const childCommentRes = await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text1) | 365 | const childCommentRes = await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text1) |
366 | const childCommentId = childCommentRes.body.comment.id | 366 | const childCommentId = childCommentRes.body.comment.id |
367 | 367 | ||
368 | const text2 = 'my super answer to answer of thread 1' | 368 | const text2 = 'my super answer to answer of thread 1' |
369 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId, text2) | 369 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, childCommentId, text2) |
370 | 370 | ||
371 | const text3 = 'my second answer to thread 1' | 371 | const text3 = 'my second answer to thread 1' |
372 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text3) | 372 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text3) |
373 | } | 373 | } |
374 | 374 | ||
375 | { | 375 | { |
376 | const text = 'will be deleted' | 376 | const text = 'will be deleted' |
377 | const res = await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, text) | 377 | const res = await addVideoCommentThread(servers[2].url, servers[2].accessToken, video4.id, text) |
378 | const threadId = res.body.comment.id | 378 | const threadId = res.body.comment.id |
379 | 379 | ||
380 | const text1 = 'answer to deleted' | 380 | const text1 = 'answer to deleted' |
381 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text1) | 381 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text1) |
382 | 382 | ||
383 | const text2 = 'will also be deleted' | 383 | const text2 = 'will also be deleted' |
384 | const childCommentRes = await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text2) | 384 | const childCommentRes = await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text2) |
385 | const childCommentId = childCommentRes.body.comment.id | 385 | const childCommentId = childCommentRes.body.comment.id |
386 | 386 | ||
387 | const text3 = 'my second answer to deleted' | 387 | const text3 = 'my second answer to deleted' |
388 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId, text3) | 388 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, childCommentId, text3) |
389 | 389 | ||
390 | await deleteVideoComment(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId) | 390 | await deleteVideoComment(servers[2].url, servers[2].accessToken, video4.id, threadId) |
391 | await deleteVideoComment(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId) | 391 | await deleteVideoComment(servers[2].url, servers[2].accessToken, video4.id, childCommentId) |
392 | } | 392 | } |
393 | } | 393 | } |
394 | 394 | ||
@@ -406,7 +406,7 @@ describe('Test follows', function () { | |||
406 | await waitJobs(servers) | 406 | await waitJobs(servers) |
407 | 407 | ||
408 | // Server 1 follows server 3 | 408 | // Server 1 follows server 3 |
409 | await follow(servers[ 0 ].url, [ servers[ 2 ].url ], servers[ 0 ].accessToken) | 409 | await follow(servers[0].url, [ servers[2].url ], servers[0].accessToken) |
410 | 410 | ||
411 | await waitJobs(servers) | 411 | await waitJobs(servers) |
412 | }) | 412 | }) |
@@ -424,7 +424,7 @@ describe('Test follows', function () { | |||
424 | }) | 424 | }) |
425 | 425 | ||
426 | it('Should have propagated videos', async function () { | 426 | it('Should have propagated videos', async function () { |
427 | const res = await getVideosList(servers[ 0 ].url) | 427 | const res = await getVideosList(servers[0].url) |
428 | expect(res.body.total).to.equal(7) | 428 | expect(res.body.total).to.equal(7) |
429 | 429 | ||
430 | const video2 = res.body.data.find(v => v.name === 'server3-2') | 430 | const video2 = res.body.data.find(v => v.name === 'server3-2') |
@@ -470,7 +470,7 @@ describe('Test follows', function () { | |||
470 | } | 470 | } |
471 | ] | 471 | ] |
472 | } | 472 | } |
473 | await completeVideoCheck(servers[ 0 ].url, video4, checkAttributes) | 473 | await completeVideoCheck(servers[0].url, video4, checkAttributes) |
474 | }) | 474 | }) |
475 | 475 | ||
476 | it('Should have propagated comments', async function () { | 476 | it('Should have propagated comments', async function () { |
@@ -481,34 +481,34 @@ describe('Test follows', function () { | |||
481 | expect(res1.body.data).to.have.lengthOf(2) | 481 | expect(res1.body.data).to.have.lengthOf(2) |
482 | 482 | ||
483 | { | 483 | { |
484 | const comment: VideoComment = res1.body.data[ 0 ] | 484 | const comment: VideoComment = res1.body.data[0] |
485 | expect(comment.inReplyToCommentId).to.be.null | 485 | expect(comment.inReplyToCommentId).to.be.null |
486 | expect(comment.text).equal('my super first comment') | 486 | expect(comment.text).equal('my super first comment') |
487 | expect(comment.videoId).to.equal(video4.id) | 487 | expect(comment.videoId).to.equal(video4.id) |
488 | expect(comment.id).to.equal(comment.threadId) | 488 | expect(comment.id).to.equal(comment.threadId) |
489 | expect(comment.account.name).to.equal('root') | 489 | expect(comment.account.name).to.equal('root') |
490 | expect(comment.account.host).to.equal('localhost:' + servers[ 2 ].port) | 490 | expect(comment.account.host).to.equal('localhost:' + servers[2].port) |
491 | expect(comment.totalReplies).to.equal(3) | 491 | expect(comment.totalReplies).to.equal(3) |
492 | expect(dateIsValid(comment.createdAt as string)).to.be.true | 492 | expect(dateIsValid(comment.createdAt as string)).to.be.true |
493 | expect(dateIsValid(comment.updatedAt as string)).to.be.true | 493 | expect(dateIsValid(comment.updatedAt as string)).to.be.true |
494 | 494 | ||
495 | const threadId = comment.threadId | 495 | const threadId = comment.threadId |
496 | 496 | ||
497 | const res2 = await getVideoThreadComments(servers[ 0 ].url, video4.id, threadId) | 497 | const res2 = await getVideoThreadComments(servers[0].url, video4.id, threadId) |
498 | 498 | ||
499 | const tree: VideoCommentThreadTree = res2.body | 499 | const tree: VideoCommentThreadTree = res2.body |
500 | expect(tree.comment.text).equal('my super first comment') | 500 | expect(tree.comment.text).equal('my super first comment') |
501 | expect(tree.children).to.have.lengthOf(2) | 501 | expect(tree.children).to.have.lengthOf(2) |
502 | 502 | ||
503 | const firstChild = tree.children[ 0 ] | 503 | const firstChild = tree.children[0] |
504 | expect(firstChild.comment.text).to.equal('my super answer to thread 1') | 504 | expect(firstChild.comment.text).to.equal('my super answer to thread 1') |
505 | expect(firstChild.children).to.have.lengthOf(1) | 505 | expect(firstChild.children).to.have.lengthOf(1) |
506 | 506 | ||
507 | const childOfFirstChild = firstChild.children[ 0 ] | 507 | const childOfFirstChild = firstChild.children[0] |
508 | expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') | 508 | expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') |
509 | expect(childOfFirstChild.children).to.have.lengthOf(0) | 509 | expect(childOfFirstChild.children).to.have.lengthOf(0) |
510 | 510 | ||
511 | const secondChild = tree.children[ 1 ] | 511 | const secondChild = tree.children[1] |
512 | expect(secondChild.comment.text).to.equal('my second answer to thread 1') | 512 | expect(secondChild.comment.text).to.equal('my second answer to thread 1') |
513 | expect(secondChild.children).to.have.lengthOf(0) | 513 | expect(secondChild.children).to.have.lengthOf(0) |
514 | } | 514 | } |
@@ -569,7 +569,7 @@ describe('Test follows', function () { | |||
569 | 569 | ||
570 | await waitJobs(servers) | 570 | await waitJobs(servers) |
571 | 571 | ||
572 | let res = await getVideosList(servers[ 0 ].url) | 572 | const res = await getVideosList(servers[0].url) |
573 | expect(res.body.total).to.equal(1) | 573 | expect(res.body.total).to.equal(1) |
574 | }) | 574 | }) |
575 | 575 | ||
diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts index 7e36067f1..2cf6e15ad 100644 --- a/server/tests/api/server/handle-down.ts +++ b/server/tests/api/server/handle-down.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -8,6 +8,7 @@ import { VideoCommentThreadTree } from '../../../../shared/models/videos/video-c | |||
8 | 8 | ||
9 | import { | 9 | import { |
10 | cleanupTests, | 10 | cleanupTests, |
11 | closeAllSequelize, | ||
11 | completeVideoCheck, | 12 | completeVideoCheck, |
12 | flushAndRunMultipleServers, | 13 | flushAndRunMultipleServers, |
13 | getVideo, | 14 | getVideo, |
@@ -17,11 +18,12 @@ import { | |||
17 | reRunServer, | 18 | reRunServer, |
18 | ServerInfo, | 19 | ServerInfo, |
19 | setAccessTokensToServers, | 20 | setAccessTokensToServers, |
21 | setActorFollowScores, | ||
20 | unfollow, | 22 | unfollow, |
21 | updateVideo, | 23 | updateVideo, |
22 | uploadVideo, uploadVideoAndGetId, | 24 | uploadVideo, |
23 | wait, | 25 | uploadVideoAndGetId, |
24 | setActorFollowScores, closeAllSequelize | 26 | wait |
25 | } from '../../../../shared/extra-utils' | 27 | } from '../../../../shared/extra-utils' |
26 | import { follow, getFollowersListPaginationAndSort } from '../../../../shared/extra-utils/server/follows' | 28 | import { follow, getFollowersListPaginationAndSort } from '../../../../shared/extra-utils/server/follows' |
27 | import { getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' | 29 | import { getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' |
@@ -44,7 +46,7 @@ describe('Test handle downs', function () { | |||
44 | let missedVideo2: Video | 46 | let missedVideo2: Video |
45 | let unlistedVideo: Video | 47 | let unlistedVideo: Video |
46 | 48 | ||
47 | let videoIdsServer1: number[] = [] | 49 | const videoIdsServer1: number[] = [] |
48 | 50 | ||
49 | const videoAttributes = { | 51 | const videoAttributes = { |
50 | name: 'my super name for server 1', | 52 | name: 'my super name for server 1', |
@@ -137,7 +139,7 @@ describe('Test handle downs', function () { | |||
137 | 139 | ||
138 | // Remove server 2 follower | 140 | // Remove server 2 follower |
139 | for (let i = 0; i < 10; i++) { | 141 | for (let i = 0; i < 10; i++) { |
140 | await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) | 142 | await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes) |
141 | } | 143 | } |
142 | 144 | ||
143 | await waitJobs(servers[0]) | 145 | await waitJobs(servers[0]) |
@@ -145,14 +147,14 @@ describe('Test handle downs', function () { | |||
145 | // Kill server 3 | 147 | // Kill server 3 |
146 | killallServers([ servers[2] ]) | 148 | killallServers([ servers[2] ]) |
147 | 149 | ||
148 | const resLastVideo1 = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) | 150 | const resLastVideo1 = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes) |
149 | missedVideo1 = resLastVideo1.body.video | 151 | missedVideo1 = resLastVideo1.body.video |
150 | 152 | ||
151 | const resLastVideo2 = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) | 153 | const resLastVideo2 = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes) |
152 | missedVideo2 = resLastVideo2.body.video | 154 | missedVideo2 = resLastVideo2.body.video |
153 | 155 | ||
154 | // Unlisted video | 156 | // Unlisted video |
155 | let resVideo = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, unlistedVideoAttributes) | 157 | const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, unlistedVideoAttributes) |
156 | unlistedVideo = resVideo.body.video | 158 | unlistedVideo = resVideo.body.video |
157 | 159 | ||
158 | // Add comments to video 2 | 160 | // Add comments to video 2 |
@@ -174,7 +176,7 @@ describe('Test handle downs', function () { | |||
174 | await wait(11000) | 176 | await wait(11000) |
175 | 177 | ||
176 | // Only server 3 is still a follower of server 1 | 178 | // Only server 3 is still a follower of server 1 |
177 | const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' }) | 179 | const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' }) |
178 | expect(res.body.data).to.be.an('array') | 180 | expect(res.body.data).to.be.an('array') |
179 | expect(res.body.data).to.have.lengthOf(1) | 181 | expect(res.body.data).to.have.lengthOf(1) |
180 | expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port) | 182 | expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port) |
@@ -185,8 +187,8 @@ describe('Test handle downs', function () { | |||
185 | 187 | ||
186 | for (const state of states) { | 188 | for (const state of states) { |
187 | const res = await getJobsListPaginationAndSort({ | 189 | const res = await getJobsListPaginationAndSort({ |
188 | url: servers[ 0 ].url, | 190 | url: servers[0].url, |
189 | accessToken: servers[ 0 ].accessToken, | 191 | accessToken: servers[0].accessToken, |
190 | state: state, | 192 | state: state, |
191 | start: 0, | 193 | start: 0, |
192 | count: 50, | 194 | count: 50, |
@@ -209,7 +211,7 @@ describe('Test handle downs', function () { | |||
209 | 211 | ||
210 | await waitJobs(servers) | 212 | await waitJobs(servers) |
211 | 213 | ||
212 | const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' }) | 214 | const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' }) |
213 | expect(res.body.data).to.be.an('array') | 215 | expect(res.body.data).to.be.an('array') |
214 | expect(res.body.data).to.have.lengthOf(2) | 216 | expect(res.body.data).to.have.lengthOf(2) |
215 | }) | 217 | }) |
@@ -221,8 +223,8 @@ describe('Test handle downs', function () { | |||
221 | expect(res1.body.data).to.be.an('array') | 223 | expect(res1.body.data).to.be.an('array') |
222 | expect(res1.body.data).to.have.lengthOf(11) | 224 | expect(res1.body.data).to.have.lengthOf(11) |
223 | 225 | ||
224 | await updateVideo(servers[0].url, servers[0].accessToken, missedVideo1.uuid, { }) | 226 | await updateVideo(servers[0].url, servers[0].accessToken, missedVideo1.uuid, {}) |
225 | await updateVideo(servers[0].url, servers[0].accessToken, unlistedVideo.uuid, { }) | 227 | await updateVideo(servers[0].url, servers[0].accessToken, unlistedVideo.uuid, {}) |
226 | 228 | ||
227 | await waitJobs(servers) | 229 | await waitJobs(servers) |
228 | 230 | ||
@@ -313,14 +315,14 @@ describe('Test handle downs', function () { | |||
313 | this.timeout(120000) | 315 | this.timeout(120000) |
314 | 316 | ||
315 | for (let i = 0; i < 10; i++) { | 317 | for (let i = 0; i < 10; i++) { |
316 | const uuid = (await uploadVideoAndGetId({ server: servers[ 0 ], videoName: 'video ' + i })).uuid | 318 | const uuid = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video ' + i })).uuid |
317 | videoIdsServer1.push(uuid) | 319 | videoIdsServer1.push(uuid) |
318 | } | 320 | } |
319 | 321 | ||
320 | await waitJobs(servers) | 322 | await waitJobs(servers) |
321 | 323 | ||
322 | for (const id of videoIdsServer1) { | 324 | for (const id of videoIdsServer1) { |
323 | await getVideo(servers[ 1 ].url, id) | 325 | await getVideo(servers[1].url, id) |
324 | } | 326 | } |
325 | 327 | ||
326 | await waitJobs(servers) | 328 | await waitJobs(servers) |
diff --git a/server/tests/api/server/jobs.ts b/server/tests/api/server/jobs.ts index 58d8c8c10..19c8836b5 100644 --- a/server/tests/api/server/jobs.ts +++ b/server/tests/api/server/jobs.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { cleanupTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index' | 5 | import { cleanupTests, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index' |
6 | import { doubleFollow } from '../../../../shared/extra-utils/server/follows' | 6 | import { doubleFollow } from '../../../../shared/extra-utils/server/follows' |
7 | import { getJobsList, getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' | 7 | import { getJobsList, getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' |
8 | import { flushAndRunMultipleServers } from '../../../../shared/extra-utils/server/servers' | 8 | import { flushAndRunMultipleServers } from '../../../../shared/extra-utils/server/servers' |
@@ -44,8 +44,8 @@ describe('Test jobs', function () { | |||
44 | it('Should list jobs with sort, pagination and job type', async function () { | 44 | it('Should list jobs with sort, pagination and job type', async function () { |
45 | { | 45 | { |
46 | const res = await getJobsListPaginationAndSort({ | 46 | const res = await getJobsListPaginationAndSort({ |
47 | url: servers[ 1 ].url, | 47 | url: servers[1].url, |
48 | accessToken: servers[ 1 ].accessToken, | 48 | accessToken: servers[1].accessToken, |
49 | state: 'completed', | 49 | state: 'completed', |
50 | start: 1, | 50 | start: 1, |
51 | count: 2, | 51 | count: 2, |
@@ -54,9 +54,9 @@ describe('Test jobs', function () { | |||
54 | expect(res.body.total).to.be.above(2) | 54 | expect(res.body.total).to.be.above(2) |
55 | expect(res.body.data).to.have.lengthOf(2) | 55 | expect(res.body.data).to.have.lengthOf(2) |
56 | 56 | ||
57 | let job: Job = res.body.data[ 0 ] | 57 | let job: Job = res.body.data[0] |
58 | // Skip repeat jobs | 58 | // Skip repeat jobs |
59 | if (job.type === 'videos-views') job = res.body.data[ 1 ] | 59 | if (job.type === 'videos-views') job = res.body.data[1] |
60 | 60 | ||
61 | expect(job.state).to.equal('completed') | 61 | expect(job.state).to.equal('completed') |
62 | expect(job.type.startsWith('activitypub-')).to.be.true | 62 | expect(job.type.startsWith('activitypub-')).to.be.true |
@@ -67,8 +67,8 @@ describe('Test jobs', function () { | |||
67 | 67 | ||
68 | { | 68 | { |
69 | const res = await getJobsListPaginationAndSort({ | 69 | const res = await getJobsListPaginationAndSort({ |
70 | url: servers[ 1 ].url, | 70 | url: servers[1].url, |
71 | accessToken: servers[ 1 ].accessToken, | 71 | accessToken: servers[1].accessToken, |
72 | state: 'completed', | 72 | state: 'completed', |
73 | start: 0, | 73 | start: 0, |
74 | count: 100, | 74 | count: 100, |
diff --git a/server/tests/api/server/logs.ts b/server/tests/api/server/logs.ts index d3c877408..b8714c7a1 100644 --- a/server/tests/api/server/logs.ts +++ b/server/tests/api/server/logs.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/server/no-client.ts b/server/tests/api/server/no-client.ts index 86edeb289..d0450aba0 100644 --- a/server/tests/api/server/no-client.ts +++ b/server/tests/api/server/no-client.ts | |||
@@ -9,7 +9,7 @@ describe('Start and stop server without web client routes', function () { | |||
9 | before(async function () { | 9 | before(async function () { |
10 | this.timeout(30000) | 10 | this.timeout(30000) |
11 | 11 | ||
12 | server = await flushAndRunServer(1, {}, ['--no-client']) | 12 | server = await flushAndRunServer(1, {}, [ '--no-client' ]) |
13 | }) | 13 | }) |
14 | 14 | ||
15 | it('Should fail getting the client', function () { | 15 | it('Should fail getting the client', function () { |
diff --git a/server/tests/api/server/plugins.ts b/server/tests/api/server/plugins.ts index b8a8a2fee..452d05012 100644 --- a/server/tests/api/server/plugins.ts +++ b/server/tests/api/server/plugins.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -6,19 +6,28 @@ import { | |||
6 | cleanupTests, | 6 | cleanupTests, |
7 | closeAllSequelize, | 7 | closeAllSequelize, |
8 | flushAndRunServer, | 8 | flushAndRunServer, |
9 | getConfig, getMyUserInformation, getPluginPackageJSON, | 9 | getConfig, |
10 | getMyUserInformation, | ||
10 | getPlugin, | 11 | getPlugin, |
12 | getPluginPackageJSON, | ||
11 | getPluginRegisteredSettings, | 13 | getPluginRegisteredSettings, |
12 | getPluginsCSS, | 14 | getPluginsCSS, |
13 | installPlugin, killallServers, | 15 | getPublicSettings, |
16 | installPlugin, | ||
17 | killallServers, | ||
14 | listAvailablePlugins, | 18 | listAvailablePlugins, |
15 | listPlugins, reRunServer, | 19 | listPlugins, |
20 | reRunServer, | ||
16 | ServerInfo, | 21 | ServerInfo, |
17 | setAccessTokensToServers, | 22 | setAccessTokensToServers, |
18 | setPluginVersion, uninstallPlugin, | 23 | setPluginVersion, |
19 | updateCustomSubConfig, updateMyUser, updatePluginPackageJSON, updatePlugin, | 24 | uninstallPlugin, |
25 | updateCustomSubConfig, | ||
26 | updateMyUser, | ||
27 | updatePlugin, | ||
28 | updatePluginPackageJSON, | ||
20 | updatePluginSettings, | 29 | updatePluginSettings, |
21 | wait, getPublicSettings | 30 | wait |
22 | } from '../../../../shared/extra-utils' | 31 | } from '../../../../shared/extra-utils' |
23 | import { PluginType } from '../../../../shared/models/plugins/plugin.type' | 32 | import { PluginType } from '../../../../shared/models/plugins/plugin.type' |
24 | import { PeerTubePluginIndex } from '../../../../shared/models/plugins/peertube-plugin-index.model' | 33 | import { PeerTubePluginIndex } from '../../../../shared/models/plugins/peertube-plugin-index.model' |
@@ -88,7 +97,7 @@ describe('Test plugins', function () { | |||
88 | expect(res2.body.total).to.be.at.least(2) | 97 | expect(res2.body.total).to.be.at.least(2) |
89 | expect(data2).to.have.lengthOf(2) | 98 | expect(data2).to.have.lengthOf(2) |
90 | 99 | ||
91 | expect(data1[0].npmName).to.not.equal(data2[ 0 ].npmName) | 100 | expect(data1[0].npmName).to.not.equal(data2[0].npmName) |
92 | } | 101 | } |
93 | 102 | ||
94 | { | 103 | { |
diff --git a/server/tests/api/server/reverse-proxy.ts b/server/tests/api/server/reverse-proxy.ts index b6b33a884..d0d79c4f6 100644 --- a/server/tests/api/server/reverse-proxy.ts +++ b/server/tests/api/server/reverse-proxy.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
diff --git a/server/tests/api/server/stats.ts b/server/tests/api/server/stats.ts index a01cd4b38..c207bb5f0 100644 --- a/server/tests/api/server/stats.ts +++ b/server/tests/api/server/stats.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -9,13 +9,12 @@ import { | |||
9 | doubleFollow, | 9 | doubleFollow, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
11 | follow, | 11 | follow, |
12 | killallServers, | ||
13 | ServerInfo, | 12 | ServerInfo, |
14 | uploadVideo, | 13 | uploadVideo, |
15 | viewVideo, | 14 | viewVideo, |
16 | wait | 15 | wait |
17 | } from '../../../../shared/extra-utils' | 16 | } from '../../../../shared/extra-utils' |
18 | import { flushTests, setAccessTokensToServers } from '../../../../shared/extra-utils/index' | 17 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/index' |
19 | import { getStats } from '../../../../shared/extra-utils/server/stats' | 18 | import { getStats } from '../../../../shared/extra-utils/server/stats' |
20 | import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments' | 19 | import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments' |
21 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 20 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
@@ -36,7 +35,7 @@ describe('Test stats (excluding redundancy)', function () { | |||
36 | username: 'user1', | 35 | username: 'user1', |
37 | password: 'super_password' | 36 | password: 'super_password' |
38 | } | 37 | } |
39 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 38 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
40 | 39 | ||
41 | const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { fixture: 'video_short.webm' }) | 40 | const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { fixture: 'video_short.webm' }) |
42 | const videoUUID = resVideo.body.video.uuid | 41 | const videoUUID = resVideo.body.video.uuid |
diff --git a/server/tests/api/server/tracker.ts b/server/tests/api/server/tracker.ts index 9d7eec8ca..9d3a274d4 100644 --- a/server/tests/api/server/tracker.ts +++ b/server/tests/api/server/tracker.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await,@typescript-eslint/no-floating-promises */ |
2 | 2 | ||
3 | import * as magnetUtil from 'magnet-uri' | 3 | import * as magnetUtil from 'magnet-uri' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/users/blocklist.ts b/server/tests/api/users/blocklist.ts index 05e58017a..21b9ae4f8 100644 --- a/server/tests/api/users/blocklist.ts +++ b/server/tests/api/users/blocklist.ts | |||
@@ -1,21 +1,20 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { AccountBlock, ServerBlock, UserNotificationType, Video } from '../../../../shared/index' | 5 | import { AccountBlock, ServerBlock, Video } from '../../../../shared/index' |
6 | import { | 6 | import { |
7 | cleanupTests, | 7 | cleanupTests, |
8 | createUser, deleteVideoComment, | 8 | createUser, |
9 | deleteVideoComment, | ||
9 | doubleFollow, | 10 | doubleFollow, |
10 | flushAndRunMultipleServers, | 11 | flushAndRunMultipleServers, |
11 | flushTests, | ||
12 | killallServers, | ||
13 | ServerInfo, | 12 | ServerInfo, |
14 | uploadVideo, | 13 | uploadVideo, |
15 | userLogin | 14 | userLogin |
16 | } from '../../../../shared/extra-utils/index' | 15 | } from '../../../../shared/extra-utils/index' |
17 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' | 16 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' |
18 | import { getVideosListWithToken, getVideosList } from '../../../../shared/extra-utils/videos/videos' | 17 | import { getVideosList, getVideosListWithToken } from '../../../../shared/extra-utils/videos/videos' |
19 | import { | 18 | import { |
20 | addVideoCommentReply, | 19 | addVideoCommentReply, |
21 | addVideoCommentThread, | 20 | addVideoCommentThread, |
@@ -79,7 +78,7 @@ async function checkCommentNotification ( | |||
79 | const resComment = await addVideoCommentThread(comment.server.url, comment.token, comment.videoUUID, comment.text) | 78 | const resComment = await addVideoCommentThread(comment.server.url, comment.token, comment.videoUUID, comment.text) |
80 | const threadId = resComment.body.comment.id | 79 | const threadId = resComment.body.comment.id |
81 | 80 | ||
82 | await waitJobs([ mainServer, comment.server]) | 81 | await waitJobs([ mainServer, comment.server ]) |
83 | 82 | ||
84 | const res = await getUserNotifications(mainServer.url, mainServer.accessToken, 0, 30) | 83 | const res = await getUserNotifications(mainServer.url, mainServer.accessToken, 0, 30) |
85 | const commentNotifications = res.body.data | 84 | const commentNotifications = res.body.data |
@@ -90,7 +89,7 @@ async function checkCommentNotification ( | |||
90 | 89 | ||
91 | await deleteVideoComment(comment.server.url, comment.token, comment.videoUUID, threadId) | 90 | await deleteVideoComment(comment.server.url, comment.token, comment.videoUUID, threadId) |
92 | 91 | ||
93 | await waitJobs([ mainServer, comment.server]) | 92 | await waitJobs([ mainServer, comment.server ]) |
94 | } | 93 | } |
95 | 94 | ||
96 | describe('Test blocklist', function () { | 95 | describe('Test blocklist', function () { |
@@ -109,7 +108,7 @@ describe('Test blocklist', function () { | |||
109 | 108 | ||
110 | { | 109 | { |
111 | const user = { username: 'user1', password: 'password' } | 110 | const user = { username: 'user1', password: 'password' } |
112 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 111 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
113 | 112 | ||
114 | userToken1 = await userLogin(servers[0], user) | 113 | userToken1 = await userLogin(servers[0], user) |
115 | await uploadVideo(servers[0].url, userToken1, { name: 'video user 1' }) | 114 | await uploadVideo(servers[0].url, userToken1, { name: 'video user 1' }) |
@@ -117,14 +116,14 @@ describe('Test blocklist', function () { | |||
117 | 116 | ||
118 | { | 117 | { |
119 | const user = { username: 'moderator', password: 'password' } | 118 | const user = { username: 'moderator', password: 'password' } |
120 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 119 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
121 | 120 | ||
122 | userModeratorToken = await userLogin(servers[0], user) | 121 | userModeratorToken = await userLogin(servers[0], user) |
123 | } | 122 | } |
124 | 123 | ||
125 | { | 124 | { |
126 | const user = { username: 'user2', password: 'password' } | 125 | const user = { username: 'user2', password: 'password' } |
127 | await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password }) | 126 | await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password }) |
128 | 127 | ||
129 | userToken2 = await userLogin(servers[1], user) | 128 | userToken2 = await userLogin(servers[1], user) |
130 | await uploadVideo(servers[1].url, userToken2, { name: 'video user 2' }) | 129 | await uploadVideo(servers[1].url, userToken2, { name: 'video user 2' }) |
@@ -143,14 +142,14 @@ describe('Test blocklist', function () { | |||
143 | await doubleFollow(servers[0], servers[1]) | 142 | await doubleFollow(servers[0], servers[1]) |
144 | 143 | ||
145 | { | 144 | { |
146 | const resComment = await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, 'comment root 1') | 145 | const resComment = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID1, 'comment root 1') |
147 | const resReply = await addVideoCommentReply(servers[ 0 ].url, userToken1, videoUUID1, resComment.body.comment.id, 'comment user 1') | 146 | const resReply = await addVideoCommentReply(servers[0].url, userToken1, videoUUID1, resComment.body.comment.id, 'comment user 1') |
148 | await addVideoCommentReply(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, resReply.body.comment.id, 'comment root 1') | 147 | await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID1, resReply.body.comment.id, 'comment root 1') |
149 | } | 148 | } |
150 | 149 | ||
151 | { | 150 | { |
152 | const resComment = await addVideoCommentThread(servers[ 0 ].url, userToken1, videoUUID1, 'comment user 1') | 151 | const resComment = await addVideoCommentThread(servers[0].url, userToken1, videoUUID1, 'comment user 1') |
153 | await addVideoCommentReply(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, resComment.body.comment.id, 'comment root 1') | 152 | await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID1, resComment.body.comment.id, 'comment root 1') |
154 | } | 153 | } |
155 | 154 | ||
156 | await waitJobs(servers) | 155 | await waitJobs(servers) |
@@ -160,19 +159,19 @@ describe('Test blocklist', function () { | |||
160 | 159 | ||
161 | describe('When managing account blocklist', function () { | 160 | describe('When managing account blocklist', function () { |
162 | it('Should list all videos', function () { | 161 | it('Should list all videos', function () { |
163 | return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken) | 162 | return checkAllVideos(servers[0].url, servers[0].accessToken) |
164 | }) | 163 | }) |
165 | 164 | ||
166 | it('Should list the comments', function () { | 165 | it('Should list the comments', function () { |
167 | return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 166 | return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
168 | }) | 167 | }) |
169 | 168 | ||
170 | it('Should block a remote account', async function () { | 169 | it('Should block a remote account', async function () { |
171 | await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) | 170 | await addAccountToAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port) |
172 | }) | 171 | }) |
173 | 172 | ||
174 | it('Should hide its videos', async function () { | 173 | it('Should hide its videos', async function () { |
175 | const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) | 174 | const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) |
176 | 175 | ||
177 | const videos: Video[] = res.body.data | 176 | const videos: Video[] = res.body.data |
178 | expect(videos).to.have.lengthOf(3) | 177 | expect(videos).to.have.lengthOf(3) |
@@ -182,11 +181,11 @@ describe('Test blocklist', function () { | |||
182 | }) | 181 | }) |
183 | 182 | ||
184 | it('Should block a local account', async function () { | 183 | it('Should block a local account', async function () { |
185 | await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') | 184 | await addAccountToAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1') |
186 | }) | 185 | }) |
187 | 186 | ||
188 | it('Should hide its videos', async function () { | 187 | it('Should hide its videos', async function () { |
189 | const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) | 188 | const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) |
190 | 189 | ||
191 | const videos: Video[] = res.body.data | 190 | const videos: Video[] = res.body.data |
192 | expect(videos).to.have.lengthOf(2) | 191 | expect(videos).to.have.lengthOf(2) |
@@ -196,17 +195,17 @@ describe('Test blocklist', function () { | |||
196 | }) | 195 | }) |
197 | 196 | ||
198 | it('Should hide its comments', async function () { | 197 | it('Should hide its comments', async function () { |
199 | const resThreads = await getVideoCommentThreads(servers[ 0 ].url, videoUUID1, 0, 5, '-createdAt', servers[ 0 ].accessToken) | 198 | const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 5, '-createdAt', servers[0].accessToken) |
200 | 199 | ||
201 | const threads: VideoComment[] = resThreads.body.data | 200 | const threads: VideoComment[] = resThreads.body.data |
202 | expect(threads).to.have.lengthOf(1) | 201 | expect(threads).to.have.lengthOf(1) |
203 | expect(threads[ 0 ].totalReplies).to.equal(0) | 202 | expect(threads[0].totalReplies).to.equal(0) |
204 | 203 | ||
205 | const t = threads.find(t => t.text === 'comment user 1') | 204 | const t = threads.find(t => t.text === 'comment user 1') |
206 | expect(t).to.be.undefined | 205 | expect(t).to.be.undefined |
207 | 206 | ||
208 | for (const thread of threads) { | 207 | for (const thread of threads) { |
209 | const res = await getVideoThreadComments(servers[ 0 ].url, videoUUID1, thread.id, servers[ 0 ].accessToken) | 208 | const res = await getVideoThreadComments(servers[0].url, videoUUID1, thread.id, servers[0].accessToken) |
210 | 209 | ||
211 | const tree: VideoCommentThreadTree = res.body | 210 | const tree: VideoCommentThreadTree = res.body |
212 | expect(tree.children).to.have.lengthOf(0) | 211 | expect(tree.children).to.have.lengthOf(0) |
@@ -217,37 +216,37 @@ describe('Test blocklist', function () { | |||
217 | this.timeout(20000) | 216 | this.timeout(20000) |
218 | 217 | ||
219 | { | 218 | { |
220 | const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } | 219 | const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } |
221 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 220 | await checkCommentNotification(servers[0], comment, 'absence') |
222 | } | 221 | } |
223 | 222 | ||
224 | { | 223 | { |
225 | const comment = { | 224 | const comment = { |
226 | server: servers[ 0 ], | 225 | server: servers[0], |
227 | token: userToken1, | 226 | token: userToken1, |
228 | videoUUID: videoUUID2, | 227 | videoUUID: videoUUID2, |
229 | text: 'hello @root@localhost:' + servers[ 0 ].port | 228 | text: 'hello @root@localhost:' + servers[0].port |
230 | } | 229 | } |
231 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 230 | await checkCommentNotification(servers[0], comment, 'absence') |
232 | } | 231 | } |
233 | }) | 232 | }) |
234 | 233 | ||
235 | it('Should list all the videos with another user', async function () { | 234 | it('Should list all the videos with another user', async function () { |
236 | return checkAllVideos(servers[ 0 ].url, userToken1) | 235 | return checkAllVideos(servers[0].url, userToken1) |
237 | }) | 236 | }) |
238 | 237 | ||
239 | it('Should list all the comments with another user', async function () { | 238 | it('Should list all the comments with another user', async function () { |
240 | return checkAllComments(servers[ 0 ].url, userToken1, videoUUID1) | 239 | return checkAllComments(servers[0].url, userToken1, videoUUID1) |
241 | }) | 240 | }) |
242 | 241 | ||
243 | it('Should list blocked accounts', async function () { | 242 | it('Should list blocked accounts', async function () { |
244 | { | 243 | { |
245 | const res = await getAccountBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') | 244 | const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt') |
246 | const blocks: AccountBlock[] = res.body.data | 245 | const blocks: AccountBlock[] = res.body.data |
247 | 246 | ||
248 | expect(res.body.total).to.equal(2) | 247 | expect(res.body.total).to.equal(2) |
249 | 248 | ||
250 | const block = blocks[ 0 ] | 249 | const block = blocks[0] |
251 | expect(block.byAccount.displayName).to.equal('root') | 250 | expect(block.byAccount.displayName).to.equal('root') |
252 | expect(block.byAccount.name).to.equal('root') | 251 | expect(block.byAccount.name).to.equal('root') |
253 | expect(block.blockedAccount.displayName).to.equal('user2') | 252 | expect(block.blockedAccount.displayName).to.equal('user2') |
@@ -256,12 +255,12 @@ describe('Test blocklist', function () { | |||
256 | } | 255 | } |
257 | 256 | ||
258 | { | 257 | { |
259 | const res = await getAccountBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 1, 2, 'createdAt') | 258 | const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 1, 2, 'createdAt') |
260 | const blocks: AccountBlock[] = res.body.data | 259 | const blocks: AccountBlock[] = res.body.data |
261 | 260 | ||
262 | expect(res.body.total).to.equal(2) | 261 | expect(res.body.total).to.equal(2) |
263 | 262 | ||
264 | const block = blocks[ 0 ] | 263 | const block = blocks[0] |
265 | expect(block.byAccount.displayName).to.equal('root') | 264 | expect(block.byAccount.displayName).to.equal('root') |
266 | expect(block.byAccount.name).to.equal('root') | 265 | expect(block.byAccount.name).to.equal('root') |
267 | expect(block.blockedAccount.displayName).to.equal('user1') | 266 | expect(block.blockedAccount.displayName).to.equal('user1') |
@@ -271,11 +270,11 @@ describe('Test blocklist', function () { | |||
271 | }) | 270 | }) |
272 | 271 | ||
273 | it('Should unblock the remote account', async function () { | 272 | it('Should unblock the remote account', async function () { |
274 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) | 273 | await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port) |
275 | }) | 274 | }) |
276 | 275 | ||
277 | it('Should display its videos', async function () { | 276 | it('Should display its videos', async function () { |
278 | const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) | 277 | const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) |
279 | 278 | ||
280 | const videos: Video[] = res.body.data | 279 | const videos: Video[] = res.body.data |
281 | expect(videos).to.have.lengthOf(3) | 280 | expect(videos).to.have.lengthOf(3) |
@@ -285,48 +284,48 @@ describe('Test blocklist', function () { | |||
285 | }) | 284 | }) |
286 | 285 | ||
287 | it('Should unblock the local account', async function () { | 286 | it('Should unblock the local account', async function () { |
288 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') | 287 | await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1') |
289 | }) | 288 | }) |
290 | 289 | ||
291 | it('Should display its comments', function () { | 290 | it('Should display its comments', function () { |
292 | return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 291 | return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
293 | }) | 292 | }) |
294 | 293 | ||
295 | it('Should have a notification from a non blocked account', async function () { | 294 | it('Should have a notification from a non blocked account', async function () { |
296 | this.timeout(20000) | 295 | this.timeout(20000) |
297 | 296 | ||
298 | { | 297 | { |
299 | const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } | 298 | const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } |
300 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 299 | await checkCommentNotification(servers[0], comment, 'presence') |
301 | } | 300 | } |
302 | 301 | ||
303 | { | 302 | { |
304 | const comment = { | 303 | const comment = { |
305 | server: servers[ 0 ], | 304 | server: servers[0], |
306 | token: userToken1, | 305 | token: userToken1, |
307 | videoUUID: videoUUID2, | 306 | videoUUID: videoUUID2, |
308 | text: 'hello @root@localhost:' + servers[ 0 ].port | 307 | text: 'hello @root@localhost:' + servers[0].port |
309 | } | 308 | } |
310 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 309 | await checkCommentNotification(servers[0], comment, 'presence') |
311 | } | 310 | } |
312 | }) | 311 | }) |
313 | }) | 312 | }) |
314 | 313 | ||
315 | describe('When managing server blocklist', function () { | 314 | describe('When managing server blocklist', function () { |
316 | it('Should list all videos', function () { | 315 | it('Should list all videos', function () { |
317 | return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken) | 316 | return checkAllVideos(servers[0].url, servers[0].accessToken) |
318 | }) | 317 | }) |
319 | 318 | ||
320 | it('Should list the comments', function () { | 319 | it('Should list the comments', function () { |
321 | return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 320 | return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
322 | }) | 321 | }) |
323 | 322 | ||
324 | it('Should block a remote server', async function () { | 323 | it('Should block a remote server', async function () { |
325 | await addServerToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 324 | await addServerToAccountBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
326 | }) | 325 | }) |
327 | 326 | ||
328 | it('Should hide its videos', async function () { | 327 | it('Should hide its videos', async function () { |
329 | const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) | 328 | const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) |
330 | 329 | ||
331 | const videos: Video[] = res.body.data | 330 | const videos: Video[] = res.body.data |
332 | expect(videos).to.have.lengthOf(2) | 331 | expect(videos).to.have.lengthOf(2) |
@@ -339,81 +338,81 @@ describe('Test blocklist', function () { | |||
339 | }) | 338 | }) |
340 | 339 | ||
341 | it('Should list all the videos with another user', async function () { | 340 | it('Should list all the videos with another user', async function () { |
342 | return checkAllVideos(servers[ 0 ].url, userToken1) | 341 | return checkAllVideos(servers[0].url, userToken1) |
343 | }) | 342 | }) |
344 | 343 | ||
345 | it('Should hide its comments', async function () { | 344 | it('Should hide its comments', async function () { |
346 | this.timeout(10000) | 345 | this.timeout(10000) |
347 | 346 | ||
348 | const resThreads = await addVideoCommentThread(servers[ 1 ].url, userToken2, videoUUID1, 'hidden comment 2') | 347 | const resThreads = await addVideoCommentThread(servers[1].url, userToken2, videoUUID1, 'hidden comment 2') |
349 | const threadId = resThreads.body.comment.id | 348 | const threadId = resThreads.body.comment.id |
350 | 349 | ||
351 | await waitJobs(servers) | 350 | await waitJobs(servers) |
352 | 351 | ||
353 | await checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 352 | await checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
354 | 353 | ||
355 | await deleteVideoComment(servers[ 1 ].url, userToken2, videoUUID1, threadId) | 354 | await deleteVideoComment(servers[1].url, userToken2, videoUUID1, threadId) |
356 | }) | 355 | }) |
357 | 356 | ||
358 | it('Should not have notifications from blocked server', async function () { | 357 | it('Should not have notifications from blocked server', async function () { |
359 | this.timeout(20000) | 358 | this.timeout(20000) |
360 | 359 | ||
361 | { | 360 | { |
362 | const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } | 361 | const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } |
363 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 362 | await checkCommentNotification(servers[0], comment, 'absence') |
364 | } | 363 | } |
365 | 364 | ||
366 | { | 365 | { |
367 | const comment = { | 366 | const comment = { |
368 | server: servers[ 1 ], | 367 | server: servers[1], |
369 | token: userToken2, | 368 | token: userToken2, |
370 | videoUUID: videoUUID1, | 369 | videoUUID: videoUUID1, |
371 | text: 'hello @root@localhost:' + servers[ 0 ].port | 370 | text: 'hello @root@localhost:' + servers[0].port |
372 | } | 371 | } |
373 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 372 | await checkCommentNotification(servers[0], comment, 'absence') |
374 | } | 373 | } |
375 | }) | 374 | }) |
376 | 375 | ||
377 | it('Should list blocked servers', async function () { | 376 | it('Should list blocked servers', async function () { |
378 | const res = await getServerBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') | 377 | const res = await getServerBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt') |
379 | const blocks: ServerBlock[] = res.body.data | 378 | const blocks: ServerBlock[] = res.body.data |
380 | 379 | ||
381 | expect(res.body.total).to.equal(1) | 380 | expect(res.body.total).to.equal(1) |
382 | 381 | ||
383 | const block = blocks[ 0 ] | 382 | const block = blocks[0] |
384 | expect(block.byAccount.displayName).to.equal('root') | 383 | expect(block.byAccount.displayName).to.equal('root') |
385 | expect(block.byAccount.name).to.equal('root') | 384 | expect(block.byAccount.name).to.equal('root') |
386 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) | 385 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) |
387 | }) | 386 | }) |
388 | 387 | ||
389 | it('Should unblock the remote server', async function () { | 388 | it('Should unblock the remote server', async function () { |
390 | await removeServerFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 389 | await removeServerFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
391 | }) | 390 | }) |
392 | 391 | ||
393 | it('Should display its videos', function () { | 392 | it('Should display its videos', function () { |
394 | return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken) | 393 | return checkAllVideos(servers[0].url, servers[0].accessToken) |
395 | }) | 394 | }) |
396 | 395 | ||
397 | it('Should display its comments', function () { | 396 | it('Should display its comments', function () { |
398 | return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 397 | return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
399 | }) | 398 | }) |
400 | 399 | ||
401 | it('Should have notification from unblocked server', async function () { | 400 | it('Should have notification from unblocked server', async function () { |
402 | this.timeout(20000) | 401 | this.timeout(20000) |
403 | 402 | ||
404 | { | 403 | { |
405 | const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } | 404 | const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } |
406 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 405 | await checkCommentNotification(servers[0], comment, 'presence') |
407 | } | 406 | } |
408 | 407 | ||
409 | { | 408 | { |
410 | const comment = { | 409 | const comment = { |
411 | server: servers[ 1 ], | 410 | server: servers[1], |
412 | token: userToken2, | 411 | token: userToken2, |
413 | videoUUID: videoUUID1, | 412 | videoUUID: videoUUID1, |
414 | text: 'hello @root@localhost:' + servers[ 0 ].port | 413 | text: 'hello @root@localhost:' + servers[0].port |
415 | } | 414 | } |
416 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 415 | await checkCommentNotification(servers[0], comment, 'presence') |
417 | } | 416 | } |
418 | }) | 417 | }) |
419 | }) | 418 | }) |
@@ -423,24 +422,24 @@ describe('Test blocklist', function () { | |||
423 | 422 | ||
424 | describe('When managing account blocklist', function () { | 423 | describe('When managing account blocklist', function () { |
425 | it('Should list all videos', async function () { | 424 | it('Should list all videos', async function () { |
426 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 425 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
427 | await checkAllVideos(servers[ 0 ].url, token) | 426 | await checkAllVideos(servers[0].url, token) |
428 | } | 427 | } |
429 | }) | 428 | }) |
430 | 429 | ||
431 | it('Should list the comments', async function () { | 430 | it('Should list the comments', async function () { |
432 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 431 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
433 | await checkAllComments(servers[ 0 ].url, token, videoUUID1) | 432 | await checkAllComments(servers[0].url, token, videoUUID1) |
434 | } | 433 | } |
435 | }) | 434 | }) |
436 | 435 | ||
437 | it('Should block a remote account', async function () { | 436 | it('Should block a remote account', async function () { |
438 | await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) | 437 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port) |
439 | }) | 438 | }) |
440 | 439 | ||
441 | it('Should hide its videos', async function () { | 440 | it('Should hide its videos', async function () { |
442 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 441 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
443 | const res = await getVideosListWithToken(servers[ 0 ].url, token) | 442 | const res = await getVideosListWithToken(servers[0].url, token) |
444 | 443 | ||
445 | const videos: Video[] = res.body.data | 444 | const videos: Video[] = res.body.data |
446 | expect(videos).to.have.lengthOf(3) | 445 | expect(videos).to.have.lengthOf(3) |
@@ -451,12 +450,12 @@ describe('Test blocklist', function () { | |||
451 | }) | 450 | }) |
452 | 451 | ||
453 | it('Should block a local account', async function () { | 452 | it('Should block a local account', async function () { |
454 | await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') | 453 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'user1') |
455 | }) | 454 | }) |
456 | 455 | ||
457 | it('Should hide its videos', async function () { | 456 | it('Should hide its videos', async function () { |
458 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 457 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
459 | const res = await getVideosListWithToken(servers[ 0 ].url, token) | 458 | const res = await getVideosListWithToken(servers[0].url, token) |
460 | 459 | ||
461 | const videos: Video[] = res.body.data | 460 | const videos: Video[] = res.body.data |
462 | expect(videos).to.have.lengthOf(2) | 461 | expect(videos).to.have.lengthOf(2) |
@@ -467,18 +466,18 @@ describe('Test blocklist', function () { | |||
467 | }) | 466 | }) |
468 | 467 | ||
469 | it('Should hide its comments', async function () { | 468 | it('Should hide its comments', async function () { |
470 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 469 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
471 | const resThreads = await getVideoCommentThreads(servers[ 0 ].url, videoUUID1, 0, 5, '-createdAt', token) | 470 | const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 5, '-createdAt', token) |
472 | 471 | ||
473 | const threads: VideoComment[] = resThreads.body.data | 472 | const threads: VideoComment[] = resThreads.body.data |
474 | expect(threads).to.have.lengthOf(1) | 473 | expect(threads).to.have.lengthOf(1) |
475 | expect(threads[ 0 ].totalReplies).to.equal(0) | 474 | expect(threads[0].totalReplies).to.equal(0) |
476 | 475 | ||
477 | const t = threads.find(t => t.text === 'comment user 1') | 476 | const t = threads.find(t => t.text === 'comment user 1') |
478 | expect(t).to.be.undefined | 477 | expect(t).to.be.undefined |
479 | 478 | ||
480 | for (const thread of threads) { | 479 | for (const thread of threads) { |
481 | const res = await getVideoThreadComments(servers[ 0 ].url, videoUUID1, thread.id, token) | 480 | const res = await getVideoThreadComments(servers[0].url, videoUUID1, thread.id, token) |
482 | 481 | ||
483 | const tree: VideoCommentThreadTree = res.body | 482 | const tree: VideoCommentThreadTree = res.body |
484 | expect(tree.children).to.have.lengthOf(0) | 483 | expect(tree.children).to.have.lengthOf(0) |
@@ -490,29 +489,29 @@ describe('Test blocklist', function () { | |||
490 | this.timeout(20000) | 489 | this.timeout(20000) |
491 | 490 | ||
492 | { | 491 | { |
493 | const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } | 492 | const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } |
494 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 493 | await checkCommentNotification(servers[0], comment, 'absence') |
495 | } | 494 | } |
496 | 495 | ||
497 | { | 496 | { |
498 | const comment = { | 497 | const comment = { |
499 | server: servers[ 1 ], | 498 | server: servers[1], |
500 | token: userToken2, | 499 | token: userToken2, |
501 | videoUUID: videoUUID1, | 500 | videoUUID: videoUUID1, |
502 | text: 'hello @root@localhost:' + servers[ 0 ].port | 501 | text: 'hello @root@localhost:' + servers[0].port |
503 | } | 502 | } |
504 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 503 | await checkCommentNotification(servers[0], comment, 'absence') |
505 | } | 504 | } |
506 | }) | 505 | }) |
507 | 506 | ||
508 | it('Should list blocked accounts', async function () { | 507 | it('Should list blocked accounts', async function () { |
509 | { | 508 | { |
510 | const res = await getAccountBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') | 509 | const res = await getAccountBlocklistByServer(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt') |
511 | const blocks: AccountBlock[] = res.body.data | 510 | const blocks: AccountBlock[] = res.body.data |
512 | 511 | ||
513 | expect(res.body.total).to.equal(2) | 512 | expect(res.body.total).to.equal(2) |
514 | 513 | ||
515 | const block = blocks[ 0 ] | 514 | const block = blocks[0] |
516 | expect(block.byAccount.displayName).to.equal('peertube') | 515 | expect(block.byAccount.displayName).to.equal('peertube') |
517 | expect(block.byAccount.name).to.equal('peertube') | 516 | expect(block.byAccount.name).to.equal('peertube') |
518 | expect(block.blockedAccount.displayName).to.equal('user2') | 517 | expect(block.blockedAccount.displayName).to.equal('user2') |
@@ -521,12 +520,12 @@ describe('Test blocklist', function () { | |||
521 | } | 520 | } |
522 | 521 | ||
523 | { | 522 | { |
524 | const res = await getAccountBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 1, 2, 'createdAt') | 523 | const res = await getAccountBlocklistByServer(servers[0].url, servers[0].accessToken, 1, 2, 'createdAt') |
525 | const blocks: AccountBlock[] = res.body.data | 524 | const blocks: AccountBlock[] = res.body.data |
526 | 525 | ||
527 | expect(res.body.total).to.equal(2) | 526 | expect(res.body.total).to.equal(2) |
528 | 527 | ||
529 | const block = blocks[ 0 ] | 528 | const block = blocks[0] |
530 | expect(block.byAccount.displayName).to.equal('peertube') | 529 | expect(block.byAccount.displayName).to.equal('peertube') |
531 | expect(block.byAccount.name).to.equal('peertube') | 530 | expect(block.byAccount.name).to.equal('peertube') |
532 | expect(block.blockedAccount.displayName).to.equal('user1') | 531 | expect(block.blockedAccount.displayName).to.equal('user1') |
@@ -536,12 +535,12 @@ describe('Test blocklist', function () { | |||
536 | }) | 535 | }) |
537 | 536 | ||
538 | it('Should unblock the remote account', async function () { | 537 | it('Should unblock the remote account', async function () { |
539 | await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) | 538 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port) |
540 | }) | 539 | }) |
541 | 540 | ||
542 | it('Should display its videos', async function () { | 541 | it('Should display its videos', async function () { |
543 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 542 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
544 | const res = await getVideosListWithToken(servers[ 0 ].url, token) | 543 | const res = await getVideosListWithToken(servers[0].url, token) |
545 | 544 | ||
546 | const videos: Video[] = res.body.data | 545 | const videos: Video[] = res.body.data |
547 | expect(videos).to.have.lengthOf(3) | 546 | expect(videos).to.have.lengthOf(3) |
@@ -552,12 +551,12 @@ describe('Test blocklist', function () { | |||
552 | }) | 551 | }) |
553 | 552 | ||
554 | it('Should unblock the local account', async function () { | 553 | it('Should unblock the local account', async function () { |
555 | await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') | 554 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'user1') |
556 | }) | 555 | }) |
557 | 556 | ||
558 | it('Should display its comments', async function () { | 557 | it('Should display its comments', async function () { |
559 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 558 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
560 | await checkAllComments(servers[ 0 ].url, token, videoUUID1) | 559 | await checkAllComments(servers[0].url, token, videoUUID1) |
561 | } | 560 | } |
562 | }) | 561 | }) |
563 | 562 | ||
@@ -565,43 +564,43 @@ describe('Test blocklist', function () { | |||
565 | this.timeout(20000) | 564 | this.timeout(20000) |
566 | 565 | ||
567 | { | 566 | { |
568 | const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'displayed comment' } | 567 | const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'displayed comment' } |
569 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 568 | await checkCommentNotification(servers[0], comment, 'presence') |
570 | } | 569 | } |
571 | 570 | ||
572 | { | 571 | { |
573 | const comment = { | 572 | const comment = { |
574 | server: servers[ 1 ], | 573 | server: servers[1], |
575 | token: userToken2, | 574 | token: userToken2, |
576 | videoUUID: videoUUID1, | 575 | videoUUID: videoUUID1, |
577 | text: 'hello @root@localhost:' + servers[ 0 ].port | 576 | text: 'hello @root@localhost:' + servers[0].port |
578 | } | 577 | } |
579 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 578 | await checkCommentNotification(servers[0], comment, 'presence') |
580 | } | 579 | } |
581 | }) | 580 | }) |
582 | }) | 581 | }) |
583 | 582 | ||
584 | describe('When managing server blocklist', function () { | 583 | describe('When managing server blocklist', function () { |
585 | it('Should list all videos', async function () { | 584 | it('Should list all videos', async function () { |
586 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 585 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
587 | await checkAllVideos(servers[ 0 ].url, token) | 586 | await checkAllVideos(servers[0].url, token) |
588 | } | 587 | } |
589 | }) | 588 | }) |
590 | 589 | ||
591 | it('Should list the comments', async function () { | 590 | it('Should list the comments', async function () { |
592 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 591 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
593 | await checkAllComments(servers[ 0 ].url, token, videoUUID1) | 592 | await checkAllComments(servers[0].url, token, videoUUID1) |
594 | } | 593 | } |
595 | }) | 594 | }) |
596 | 595 | ||
597 | it('Should block a remote server', async function () { | 596 | it('Should block a remote server', async function () { |
598 | await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 597 | await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
599 | }) | 598 | }) |
600 | 599 | ||
601 | it('Should hide its videos', async function () { | 600 | it('Should hide its videos', async function () { |
602 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 601 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
603 | const res1 = await getVideosList(servers[ 0 ].url) | 602 | const res1 = await getVideosList(servers[0].url) |
604 | const res2 = await getVideosListWithToken(servers[ 0 ].url, token) | 603 | const res2 = await getVideosListWithToken(servers[0].url, token) |
605 | 604 | ||
606 | for (const res of [ res1, res2 ]) { | 605 | for (const res of [ res1, res2 ]) { |
607 | const videos: Video[] = res.body.data | 606 | const videos: Video[] = res.body.data |
@@ -619,60 +618,60 @@ describe('Test blocklist', function () { | |||
619 | it('Should hide its comments', async function () { | 618 | it('Should hide its comments', async function () { |
620 | this.timeout(10000) | 619 | this.timeout(10000) |
621 | 620 | ||
622 | const resThreads = await addVideoCommentThread(servers[ 1 ].url, userToken2, videoUUID1, 'hidden comment 2') | 621 | const resThreads = await addVideoCommentThread(servers[1].url, userToken2, videoUUID1, 'hidden comment 2') |
623 | const threadId = resThreads.body.comment.id | 622 | const threadId = resThreads.body.comment.id |
624 | 623 | ||
625 | await waitJobs(servers) | 624 | await waitJobs(servers) |
626 | 625 | ||
627 | await checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 626 | await checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
628 | 627 | ||
629 | await deleteVideoComment(servers[ 1 ].url, userToken2, videoUUID1, threadId) | 628 | await deleteVideoComment(servers[1].url, userToken2, videoUUID1, threadId) |
630 | }) | 629 | }) |
631 | 630 | ||
632 | it('Should not have notification from blocked instances by instance', async function () { | 631 | it('Should not have notification from blocked instances by instance', async function () { |
633 | this.timeout(20000) | 632 | this.timeout(20000) |
634 | 633 | ||
635 | { | 634 | { |
636 | const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } | 635 | const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } |
637 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 636 | await checkCommentNotification(servers[0], comment, 'absence') |
638 | } | 637 | } |
639 | 638 | ||
640 | { | 639 | { |
641 | const comment = { | 640 | const comment = { |
642 | server: servers[ 1 ], | 641 | server: servers[1], |
643 | token: userToken2, | 642 | token: userToken2, |
644 | videoUUID: videoUUID1, | 643 | videoUUID: videoUUID1, |
645 | text: 'hello @root@localhost:' + servers[ 0 ].port | 644 | text: 'hello @root@localhost:' + servers[0].port |
646 | } | 645 | } |
647 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 646 | await checkCommentNotification(servers[0], comment, 'absence') |
648 | } | 647 | } |
649 | }) | 648 | }) |
650 | 649 | ||
651 | it('Should list blocked servers', async function () { | 650 | it('Should list blocked servers', async function () { |
652 | const res = await getServerBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') | 651 | const res = await getServerBlocklistByServer(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt') |
653 | const blocks: ServerBlock[] = res.body.data | 652 | const blocks: ServerBlock[] = res.body.data |
654 | 653 | ||
655 | expect(res.body.total).to.equal(1) | 654 | expect(res.body.total).to.equal(1) |
656 | 655 | ||
657 | const block = blocks[ 0 ] | 656 | const block = blocks[0] |
658 | expect(block.byAccount.displayName).to.equal('peertube') | 657 | expect(block.byAccount.displayName).to.equal('peertube') |
659 | expect(block.byAccount.name).to.equal('peertube') | 658 | expect(block.byAccount.name).to.equal('peertube') |
660 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) | 659 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) |
661 | }) | 660 | }) |
662 | 661 | ||
663 | it('Should unblock the remote server', async function () { | 662 | it('Should unblock the remote server', async function () { |
664 | await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 663 | await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
665 | }) | 664 | }) |
666 | 665 | ||
667 | it('Should list all videos', async function () { | 666 | it('Should list all videos', async function () { |
668 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 667 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
669 | await checkAllVideos(servers[ 0 ].url, token) | 668 | await checkAllVideos(servers[0].url, token) |
670 | } | 669 | } |
671 | }) | 670 | }) |
672 | 671 | ||
673 | it('Should list the comments', async function () { | 672 | it('Should list the comments', async function () { |
674 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 673 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
675 | await checkAllComments(servers[ 0 ].url, token, videoUUID1) | 674 | await checkAllComments(servers[0].url, token, videoUUID1) |
676 | } | 675 | } |
677 | }) | 676 | }) |
678 | 677 | ||
@@ -680,18 +679,18 @@ describe('Test blocklist', function () { | |||
680 | this.timeout(20000) | 679 | this.timeout(20000) |
681 | 680 | ||
682 | { | 681 | { |
683 | const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } | 682 | const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } |
684 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 683 | await checkCommentNotification(servers[0], comment, 'presence') |
685 | } | 684 | } |
686 | 685 | ||
687 | { | 686 | { |
688 | const comment = { | 687 | const comment = { |
689 | server: servers[ 1 ], | 688 | server: servers[1], |
690 | token: userToken2, | 689 | token: userToken2, |
691 | videoUUID: videoUUID1, | 690 | videoUUID: videoUUID1, |
692 | text: 'hello @root@localhost:' + servers[ 0 ].port | 691 | text: 'hello @root@localhost:' + servers[0].port |
693 | } | 692 | } |
694 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 693 | await checkCommentNotification(servers[0], comment, 'presence') |
695 | } | 694 | } |
696 | }) | 695 | }) |
697 | }) | 696 | }) |
diff --git a/server/tests/api/users/user-subscriptions.ts b/server/tests/api/users/user-subscriptions.ts index 08017f89c..7d6b0c6a9 100644 --- a/server/tests/api/users/user-subscriptions.ts +++ b/server/tests/api/users/user-subscriptions.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -13,16 +13,17 @@ import { | |||
13 | updateVideo, | 13 | updateVideo, |
14 | userLogin | 14 | userLogin |
15 | } from '../../../../shared/extra-utils' | 15 | } from '../../../../shared/extra-utils' |
16 | import { killallServers, ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index' | 16 | import { ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index' |
17 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' | 17 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' |
18 | import { Video, VideoChannel } from '../../../../shared/models/videos' | 18 | import { Video, VideoChannel } from '../../../../shared/models/videos' |
19 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 19 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
20 | import { | 20 | import { |
21 | addUserSubscription, | 21 | addUserSubscription, |
22 | areSubscriptionsExist, | ||
23 | getUserSubscription, | ||
22 | listUserSubscriptions, | 24 | listUserSubscriptions, |
23 | listUserSubscriptionVideos, | 25 | listUserSubscriptionVideos, |
24 | removeUserSubscription, | 26 | removeUserSubscription |
25 | getUserSubscription, areSubscriptionsExist | ||
26 | } from '../../../../shared/extra-utils/users/user-subscriptions' | 27 | } from '../../../../shared/extra-utils/users/user-subscriptions' |
27 | 28 | ||
28 | const expect = chai.expect | 29 | const expect = chai.expect |
@@ -116,7 +117,7 @@ describe('Test users subscriptions', function () { | |||
116 | 117 | ||
117 | it('Should get subscription', async function () { | 118 | it('Should get subscription', async function () { |
118 | { | 119 | { |
119 | const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:' + servers[2].port) | 120 | const res = await getUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port) |
120 | const videoChannel: VideoChannel = res.body | 121 | const videoChannel: VideoChannel = res.body |
121 | 122 | ||
122 | expect(videoChannel.name).to.equal('user3_channel') | 123 | expect(videoChannel.name).to.equal('user3_channel') |
@@ -127,7 +128,7 @@ describe('Test users subscriptions', function () { | |||
127 | } | 128 | } |
128 | 129 | ||
129 | { | 130 | { |
130 | const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:' + servers[0].port) | 131 | const res = await getUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:' + servers[0].port) |
131 | const videoChannel: VideoChannel = res.body | 132 | const videoChannel: VideoChannel = res.body |
132 | 133 | ||
133 | expect(videoChannel.name).to.equal('root_channel') | 134 | expect(videoChannel.name).to.equal('root_channel') |
@@ -146,7 +147,7 @@ describe('Test users subscriptions', function () { | |||
146 | 'user3_channel@localhost:' + servers[0].port | 147 | 'user3_channel@localhost:' + servers[0].port |
147 | ] | 148 | ] |
148 | 149 | ||
149 | const res = await areSubscriptionsExist(servers[ 0 ].url, users[ 0 ].accessToken, uris) | 150 | const res = await areSubscriptionsExist(servers[0].url, users[0].accessToken, uris) |
150 | const body = res.body | 151 | const body = res.body |
151 | 152 | ||
152 | expect(body['user3_channel@localhost:' + servers[2].port]).to.be.true | 153 | expect(body['user3_channel@localhost:' + servers[2].port]).to.be.true |
diff --git a/server/tests/api/users/users-multiple-servers.ts b/server/tests/api/users/users-multiple-servers.ts index 791418318..591ce4959 100644 --- a/server/tests/api/users/users-multiple-servers.ts +++ b/server/tests/api/users/users-multiple-servers.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -57,17 +57,17 @@ describe('Test users with multiple servers', function () { | |||
57 | password: 'password' | 57 | password: 'password' |
58 | } | 58 | } |
59 | const res = await createUser({ | 59 | const res = await createUser({ |
60 | url: servers[ 0 ].url, | 60 | url: servers[0].url, |
61 | accessToken: servers[ 0 ].accessToken, | 61 | accessToken: servers[0].accessToken, |
62 | username: user.username, | 62 | username: user.username, |
63 | password: user.password | 63 | password: user.password |
64 | }) | 64 | }) |
65 | userId = res.body.user.id | 65 | userId = res.body.user.id |
66 | userAccessToken = await userLogin(servers[ 0 ], user) | 66 | userAccessToken = await userLogin(servers[0], user) |
67 | } | 67 | } |
68 | 68 | ||
69 | { | 69 | { |
70 | const resVideo = await uploadVideo(servers[ 0 ].url, userAccessToken, {}) | 70 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, {}) |
71 | videoUUID = resVideo.body.video.uuid | 71 | videoUUID = resVideo.body.video.uuid |
72 | } | 72 | } |
73 | 73 | ||
@@ -86,7 +86,6 @@ describe('Test users with multiple servers', function () { | |||
86 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) | 86 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) |
87 | user = res.body | 87 | user = res.body |
88 | 88 | ||
89 | const account: Account = user.account | ||
90 | expect(user.account.displayName).to.equal('my super display name') | 89 | expect(user.account.displayName).to.equal('my super display name') |
91 | 90 | ||
92 | await waitJobs(servers) | 91 | await waitJobs(servers) |
diff --git a/server/tests/api/users/users-verification.ts b/server/tests/api/users/users-verification.ts index 7cd61f539..675ebf690 100644 --- a/server/tests/api/users/users-verification.ts +++ b/server/tests/api/users/users-verification.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index 24203a731..502eac0bb 100644 --- a/server/tests/api/users/users.ts +++ b/server/tests/api/users/users.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { User, UserRole, Video, MyUser, VideoPlaylistType } from '../../../../shared/index' | 5 | import { MyUser, User, UserRole, Video, VideoPlaylistType } from '../../../../shared/index' |
6 | import { | 6 | import { |
7 | blockUser, | 7 | blockUser, |
8 | cleanupTests, | 8 | cleanupTests, |
@@ -18,7 +18,8 @@ import { | |||
18 | getUsersList, | 18 | getUsersList, |
19 | getUsersListPaginationAndSort, | 19 | getUsersListPaginationAndSort, |
20 | getVideoChannel, | 20 | getVideoChannel, |
21 | getVideosList, installPlugin, | 21 | getVideosList, |
22 | installPlugin, | ||
22 | login, | 23 | login, |
23 | makePutBodyRequest, | 24 | makePutBodyRequest, |
24 | rateVideo, | 25 | rateVideo, |
@@ -121,13 +122,13 @@ describe('Test users', function () { | |||
121 | 122 | ||
122 | it('Should be able to login with an insensitive username', async function () { | 123 | it('Should be able to login with an insensitive username', async function () { |
123 | const user = { username: 'RoOt', password: server.user.password } | 124 | const user = { username: 'RoOt', password: server.user.password } |
124 | const res = await login(server.url, server.client, user, 200) | 125 | await login(server.url, server.client, user, 200) |
125 | 126 | ||
126 | const user2 = { username: 'rOoT', password: server.user.password } | 127 | const user2 = { username: 'rOoT', password: server.user.password } |
127 | const res2 = await login(server.url, server.client, user2, 200) | 128 | await login(server.url, server.client, user2, 200) |
128 | 129 | ||
129 | const user3 = { username: 'ROOt', password: server.user.password } | 130 | const user3 = { username: 'ROOt', password: server.user.password } |
130 | const res3 = await login(server.url, server.client, user3, 200) | 131 | await login(server.url, server.client, user3, 200) |
131 | }) | 132 | }) |
132 | }) | 133 | }) |
133 | 134 | ||
@@ -137,7 +138,7 @@ describe('Test users', function () { | |||
137 | const videoAttributes = {} | 138 | const videoAttributes = {} |
138 | await uploadVideo(server.url, accessToken, videoAttributes) | 139 | await uploadVideo(server.url, accessToken, videoAttributes) |
139 | const res = await getVideosList(server.url) | 140 | const res = await getVideosList(server.url) |
140 | const video = res.body.data[ 0 ] | 141 | const video = res.body.data[0] |
141 | 142 | ||
142 | expect(video.account.name).to.equal('root') | 143 | expect(video.account.name).to.equal('root') |
143 | videoId = video.id | 144 | videoId = video.id |
@@ -167,8 +168,8 @@ describe('Test users', function () { | |||
167 | const ratings = res.body | 168 | const ratings = res.body |
168 | 169 | ||
169 | expect(ratings.total).to.equal(1) | 170 | expect(ratings.total).to.equal(1) |
170 | expect(ratings.data[ 0 ].video.id).to.equal(videoId) | 171 | expect(ratings.data[0].video.id).to.equal(videoId) |
171 | expect(ratings.data[ 0 ].rating).to.equal('like') | 172 | expect(ratings.data[0].rating).to.equal('like') |
172 | }) | 173 | }) |
173 | 174 | ||
174 | it('Should retrieve ratings list by rating type', async function () { | 175 | it('Should retrieve ratings list by rating type', async function () { |
@@ -307,7 +308,7 @@ describe('Test users', function () { | |||
307 | const videos = res.body.data | 308 | const videos = res.body.data |
308 | expect(videos).to.have.lengthOf(1) | 309 | expect(videos).to.have.lengthOf(1) |
309 | 310 | ||
310 | const video: Video = videos[ 0 ] | 311 | const video: Video = videos[0] |
311 | expect(video.name).to.equal('super user video') | 312 | expect(video.name).to.equal('super user video') |
312 | expect(video.thumbnailPath).to.not.be.null | 313 | expect(video.thumbnailPath).to.not.be.null |
313 | expect(video.previewPath).to.not.be.null | 314 | expect(video.previewPath).to.not.be.null |
@@ -344,12 +345,12 @@ describe('Test users', function () { | |||
344 | expect(users).to.be.an('array') | 345 | expect(users).to.be.an('array') |
345 | expect(users.length).to.equal(2) | 346 | expect(users.length).to.equal(2) |
346 | 347 | ||
347 | const user = users[ 0 ] | 348 | const user = users[0] |
348 | expect(user.username).to.equal('user_1') | 349 | expect(user.username).to.equal('user_1') |
349 | expect(user.email).to.equal('user_1@example.com') | 350 | expect(user.email).to.equal('user_1@example.com') |
350 | expect(user.nsfwPolicy).to.equal('display') | 351 | expect(user.nsfwPolicy).to.equal('display') |
351 | 352 | ||
352 | const rootUser = users[ 1 ] | 353 | const rootUser = users[1] |
353 | expect(rootUser.username).to.equal('root') | 354 | expect(rootUser.username).to.equal('root') |
354 | expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com') | 355 | expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com') |
355 | expect(user.nsfwPolicy).to.equal('display') | 356 | expect(user.nsfwPolicy).to.equal('display') |
@@ -367,7 +368,7 @@ describe('Test users', function () { | |||
367 | expect(total).to.equal(2) | 368 | expect(total).to.equal(2) |
368 | expect(users.length).to.equal(1) | 369 | expect(users.length).to.equal(1) |
369 | 370 | ||
370 | const user = users[ 0 ] | 371 | const user = users[0] |
371 | expect(user.username).to.equal('root') | 372 | expect(user.username).to.equal('root') |
372 | expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com') | 373 | expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com') |
373 | expect(user.roleLabel).to.equal('Administrator') | 374 | expect(user.roleLabel).to.equal('Administrator') |
@@ -383,7 +384,7 @@ describe('Test users', function () { | |||
383 | expect(total).to.equal(2) | 384 | expect(total).to.equal(2) |
384 | expect(users.length).to.equal(1) | 385 | expect(users.length).to.equal(1) |
385 | 386 | ||
386 | const user = users[ 0 ] | 387 | const user = users[0] |
387 | expect(user.username).to.equal('user_1') | 388 | expect(user.username).to.equal('user_1') |
388 | expect(user.email).to.equal('user_1@example.com') | 389 | expect(user.email).to.equal('user_1@example.com') |
389 | expect(user.nsfwPolicy).to.equal('display') | 390 | expect(user.nsfwPolicy).to.equal('display') |
@@ -398,7 +399,7 @@ describe('Test users', function () { | |||
398 | expect(total).to.equal(2) | 399 | expect(total).to.equal(2) |
399 | expect(users.length).to.equal(1) | 400 | expect(users.length).to.equal(1) |
400 | 401 | ||
401 | const user = users[ 0 ] | 402 | const user = users[0] |
402 | expect(user.username).to.equal('user_1') | 403 | expect(user.username).to.equal('user_1') |
403 | expect(user.email).to.equal('user_1@example.com') | 404 | expect(user.email).to.equal('user_1@example.com') |
404 | expect(user.nsfwPolicy).to.equal('display') | 405 | expect(user.nsfwPolicy).to.equal('display') |
@@ -413,13 +414,13 @@ describe('Test users', function () { | |||
413 | expect(total).to.equal(2) | 414 | expect(total).to.equal(2) |
414 | expect(users.length).to.equal(2) | 415 | expect(users.length).to.equal(2) |
415 | 416 | ||
416 | expect(users[ 0 ].username).to.equal('root') | 417 | expect(users[0].username).to.equal('root') |
417 | expect(users[ 0 ].email).to.equal('admin' + server.internalServerNumber + '@example.com') | 418 | expect(users[0].email).to.equal('admin' + server.internalServerNumber + '@example.com') |
418 | expect(users[ 0 ].nsfwPolicy).to.equal('display') | 419 | expect(users[0].nsfwPolicy).to.equal('display') |
419 | 420 | ||
420 | expect(users[ 1 ].username).to.equal('user_1') | 421 | expect(users[1].username).to.equal('user_1') |
421 | expect(users[ 1 ].email).to.equal('user_1@example.com') | 422 | expect(users[1].email).to.equal('user_1@example.com') |
422 | expect(users[ 1 ].nsfwPolicy).to.equal('display') | 423 | expect(users[1].nsfwPolicy).to.equal('display') |
423 | }) | 424 | }) |
424 | 425 | ||
425 | it('Should search user by username', async function () { | 426 | it('Should search user by username', async function () { |
@@ -429,7 +430,7 @@ describe('Test users', function () { | |||
429 | expect(res.body.total).to.equal(1) | 430 | expect(res.body.total).to.equal(1) |
430 | expect(users.length).to.equal(1) | 431 | expect(users.length).to.equal(1) |
431 | 432 | ||
432 | expect(users[ 0 ].username).to.equal('root') | 433 | expect(users[0].username).to.equal('root') |
433 | }) | 434 | }) |
434 | 435 | ||
435 | it('Should search user by email', async function () { | 436 | it('Should search user by email', async function () { |
@@ -440,8 +441,8 @@ describe('Test users', function () { | |||
440 | expect(res.body.total).to.equal(1) | 441 | expect(res.body.total).to.equal(1) |
441 | expect(users.length).to.equal(1) | 442 | expect(users.length).to.equal(1) |
442 | 443 | ||
443 | expect(users[ 0 ].username).to.equal('user_1') | 444 | expect(users[0].username).to.equal('user_1') |
444 | expect(users[ 0 ].email).to.equal('user_1@example.com') | 445 | expect(users[0].email).to.equal('user_1@example.com') |
445 | } | 446 | } |
446 | 447 | ||
447 | { | 448 | { |
@@ -451,8 +452,8 @@ describe('Test users', function () { | |||
451 | expect(res.body.total).to.equal(2) | 452 | expect(res.body.total).to.equal(2) |
452 | expect(users.length).to.equal(2) | 453 | expect(users.length).to.equal(2) |
453 | 454 | ||
454 | expect(users[ 0 ].username).to.equal('root') | 455 | expect(users[0].username).to.equal('root') |
455 | expect(users[ 1 ].username).to.equal('user_1') | 456 | expect(users[1].username).to.equal('user_1') |
456 | } | 457 | } |
457 | }) | 458 | }) |
458 | }) | 459 | }) |
@@ -691,7 +692,7 @@ describe('Test users', function () { | |||
691 | 692 | ||
692 | expect(res.body.total).to.equal(1) | 693 | expect(res.body.total).to.equal(1) |
693 | 694 | ||
694 | const video = res.body.data[ 0 ] | 695 | const video = res.body.data[0] |
695 | expect(video.account.name).to.equal('root') | 696 | expect(video.account.name).to.equal('root') |
696 | }) | 697 | }) |
697 | }) | 698 | }) |
diff --git a/server/tests/api/videos/audio-only.ts b/server/tests/api/videos/audio-only.ts index f12d730cc..ac7a0b89c 100644 --- a/server/tests/api/videos/audio-only.ts +++ b/server/tests/api/videos/audio-only.ts | |||
@@ -1,28 +1,21 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | checkDirectoryIsEmpty, | ||
7 | checkSegmentHash, | ||
8 | checkTmpIsEmpty, | ||
9 | cleanupTests, | 6 | cleanupTests, |
10 | doubleFollow, | 7 | doubleFollow, |
11 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
12 | getPlaylist, | 9 | getVideo, |
13 | getVideo, makeGetRequest, makeRawRequest, | 10 | root, |
14 | removeVideo, root, | ||
15 | ServerInfo, | 11 | ServerInfo, |
16 | setAccessTokensToServers, updateCustomSubConfig, | 12 | setAccessTokensToServers, |
17 | updateVideo, | ||
18 | uploadVideo, | 13 | uploadVideo, |
19 | waitJobs, webtorrentAdd | 14 | waitJobs |
20 | } from '../../../../shared/extra-utils' | 15 | } from '../../../../shared/extra-utils' |
21 | import { VideoDetails } from '../../../../shared/models/videos' | 16 | import { VideoDetails } from '../../../../shared/models/videos' |
22 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' | ||
23 | import { join } from 'path' | 17 | import { join } from 'path' |
24 | import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' | 18 | import { audio, getVideoStreamSize } from '@server/helpers/ffmpeg-utils' |
25 | import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution, audio, getVideoStreamSize } from '@server/helpers/ffmpeg-utils' | ||
26 | 19 | ||
27 | const expect = chai.expect | 20 | const expect = chai.expect |
28 | 21 | ||
@@ -87,14 +80,14 @@ describe('Test audio only video transcoding', function () { | |||
87 | 80 | ||
88 | it('0p transcoded video should not have video', async function () { | 81 | it('0p transcoded video should not have video', async function () { |
89 | const paths = [ | 82 | const paths = [ |
90 | join(root(), 'test' + servers[ 0 ].internalServerNumber, 'videos', videoUUID + '-0.mp4'), | 83 | join(root(), 'test' + servers[0].internalServerNumber, 'videos', videoUUID + '-0.mp4'), |
91 | join(root(), 'test' + servers[ 0 ].internalServerNumber, 'streaming-playlists', 'hls', videoUUID, videoUUID + '-0-fragmented.mp4') | 84 | join(root(), 'test' + servers[0].internalServerNumber, 'streaming-playlists', 'hls', videoUUID, videoUUID + '-0-fragmented.mp4') |
92 | ] | 85 | ] |
93 | 86 | ||
94 | for (const path of paths) { | 87 | for (const path of paths) { |
95 | const { audioStream } = await audio.get(path) | 88 | const { audioStream } = await audio.get(path) |
96 | expect(audioStream[ 'codec_name' ]).to.be.equal('aac') | 89 | expect(audioStream['codec_name']).to.be.equal('aac') |
97 | expect(audioStream[ 'bit_rate' ]).to.be.at.most(384 * 8000) | 90 | expect(audioStream['bit_rate']).to.be.at.most(384 * 8000) |
98 | 91 | ||
99 | const size = await getVideoStreamSize(path) | 92 | const size = await getVideoStreamSize(path) |
100 | expect(size.height).to.equal(0) | 93 | expect(size.height).to.equal(0) |
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts index fa3e250ec..e3029f1ae 100644 --- a/server/tests/api/videos/multiple-servers.ts +++ b/server/tests/api/videos/multiple-servers.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -63,9 +63,9 @@ describe('Test multiple servers', function () { | |||
63 | displayName: 'my channel', | 63 | displayName: 'my channel', |
64 | description: 'super channel' | 64 | description: 'super channel' |
65 | } | 65 | } |
66 | await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel) | 66 | await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel) |
67 | const channelRes = await getVideoChannelsList(servers[ 0 ].url, 0, 1) | 67 | const channelRes = await getVideoChannelsList(servers[0].url, 0, 1) |
68 | videoChannelId = channelRes.body.data[ 0 ].id | 68 | videoChannelId = channelRes.body.data[0].id |
69 | } | 69 | } |
70 | 70 | ||
71 | // Server 1 and server 2 follow each other | 71 | // Server 1 and server 2 follow each other |
@@ -163,7 +163,7 @@ describe('Test multiple servers', function () { | |||
163 | username: 'user1', | 163 | username: 'user1', |
164 | password: 'super_password' | 164 | password: 'super_password' |
165 | } | 165 | } |
166 | await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password }) | 166 | await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password }) |
167 | const userAccessToken = await userLogin(servers[1], user) | 167 | const userAccessToken = await userLogin(servers[1], user) |
168 | 168 | ||
169 | const videoAttributes = { | 169 | const videoAttributes = { |
@@ -762,12 +762,12 @@ describe('Test multiple servers', function () { | |||
762 | 762 | ||
763 | { | 763 | { |
764 | const text = 'my super first comment' | 764 | const text = 'my super first comment' |
765 | await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, text) | 765 | await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, text) |
766 | } | 766 | } |
767 | 767 | ||
768 | { | 768 | { |
769 | const text = 'my super second comment' | 769 | const text = 'my super second comment' |
770 | await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, text) | 770 | await addVideoCommentThread(servers[2].url, servers[2].accessToken, videoUUID, text) |
771 | } | 771 | } |
772 | 772 | ||
773 | await waitJobs(servers) | 773 | await waitJobs(servers) |
@@ -777,7 +777,7 @@ describe('Test multiple servers', function () { | |||
777 | const threadId = res.body.data.find(c => c.text === 'my super first comment').id | 777 | const threadId = res.body.data.find(c => c.text === 'my super first comment').id |
778 | 778 | ||
779 | const text = 'my super answer to thread 1' | 779 | const text = 'my super answer to thread 1' |
780 | await addVideoCommentReply(servers[ 1 ].url, servers[ 1 ].accessToken, videoUUID, threadId, text) | 780 | await addVideoCommentReply(servers[1].url, servers[1].accessToken, videoUUID, threadId, text) |
781 | } | 781 | } |
782 | 782 | ||
783 | await waitJobs(servers) | 783 | await waitJobs(servers) |
@@ -790,10 +790,10 @@ describe('Test multiple servers', function () { | |||
790 | const childCommentId = res2.body.children[0].comment.id | 790 | const childCommentId = res2.body.children[0].comment.id |
791 | 791 | ||
792 | const text3 = 'my second answer to thread 1' | 792 | const text3 = 'my second answer to thread 1' |
793 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, threadId, text3) | 793 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, videoUUID, threadId, text3) |
794 | 794 | ||
795 | const text2 = 'my super answer to answer of thread 1' | 795 | const text2 = 'my super answer to answer of thread 1' |
796 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, childCommentId, text2) | 796 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, videoUUID, childCommentId, text2) |
797 | } | 797 | } |
798 | 798 | ||
799 | await waitJobs(servers) | 799 | await waitJobs(servers) |
@@ -900,9 +900,9 @@ describe('Test multiple servers', function () { | |||
900 | it('Should delete the thread comments', async function () { | 900 | it('Should delete the thread comments', async function () { |
901 | this.timeout(10000) | 901 | this.timeout(10000) |
902 | 902 | ||
903 | const res = await getVideoCommentThreads(servers[ 0 ].url, videoUUID, 0, 5) | 903 | const res = await getVideoCommentThreads(servers[0].url, videoUUID, 0, 5) |
904 | const threadId = res.body.data.find(c => c.text === 'my super first comment').id | 904 | const threadId = res.body.data.find(c => c.text === 'my super first comment').id |
905 | await deleteVideoComment(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, threadId) | 905 | await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId) |
906 | 906 | ||
907 | await waitJobs(servers) | 907 | await waitJobs(servers) |
908 | }) | 908 | }) |
@@ -945,9 +945,9 @@ describe('Test multiple servers', function () { | |||
945 | it('Should delete a remote thread by the origin server', async function () { | 945 | it('Should delete a remote thread by the origin server', async function () { |
946 | this.timeout(5000) | 946 | this.timeout(5000) |
947 | 947 | ||
948 | const res = await getVideoCommentThreads(servers[ 0 ].url, videoUUID, 0, 5) | 948 | const res = await getVideoCommentThreads(servers[0].url, videoUUID, 0, 5) |
949 | const threadId = res.body.data.find(c => c.text === 'my super second comment').id | 949 | const threadId = res.body.data.find(c => c.text === 'my super second comment').id |
950 | await deleteVideoComment(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, threadId) | 950 | await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId) |
951 | 951 | ||
952 | await waitJobs(servers) | 952 | await waitJobs(servers) |
953 | }) | 953 | }) |
@@ -1021,7 +1021,7 @@ describe('Test multiple servers', function () { | |||
1021 | const filePath = join(__dirname, '..', '..', 'fixtures', 'video_short.webm') | 1021 | const filePath = join(__dirname, '..', '..', 'fixtures', 'video_short.webm') |
1022 | 1022 | ||
1023 | await req.attach('videofile', filePath) | 1023 | await req.attach('videofile', filePath) |
1024 | .expect(200) | 1024 | .expect(200) |
1025 | 1025 | ||
1026 | await waitJobs(servers) | 1026 | await waitJobs(servers) |
1027 | 1027 | ||
@@ -1046,7 +1046,7 @@ describe('Test multiple servers', function () { | |||
1046 | duration: 5, | 1046 | duration: 5, |
1047 | commentsEnabled: true, | 1047 | commentsEnabled: true, |
1048 | downloadEnabled: true, | 1048 | downloadEnabled: true, |
1049 | tags: [ ], | 1049 | tags: [], |
1050 | privacy: VideoPrivacy.PUBLIC, | 1050 | privacy: VideoPrivacy.PUBLIC, |
1051 | channel: { | 1051 | channel: { |
1052 | displayName: 'Main root channel', | 1052 | displayName: 'Main root channel', |
diff --git a/server/tests/api/videos/services.ts b/server/tests/api/videos/services.ts index 17172331f..5505a845a 100644 --- a/server/tests/api/videos/services.ts +++ b/server/tests/api/videos/services.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -31,8 +31,8 @@ describe('Test services', function () { | |||
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:${server.port}/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:' + server.port + '/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) |
@@ -53,8 +53,8 @@ describe('Test services', function () { | |||
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:${server.port}/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) |
60 | expect(res.body.title).to.equal(server.video.name) | 60 | expect(res.body.title).to.equal(server.video.name) |
diff --git a/server/tests/api/videos/single-server.ts b/server/tests/api/videos/single-server.ts index 362d6b78f..596fff996 100644 --- a/server/tests/api/videos/single-server.ts +++ b/server/tests/api/videos/single-server.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import { keyBy } from 'lodash' | 4 | import { keyBy } from 'lodash' |
diff --git a/server/tests/api/videos/video-abuse.ts b/server/tests/api/videos/video-abuse.ts index 0cd6f22c7..cd6df7267 100644 --- a/server/tests/api/videos/video-abuse.ts +++ b/server/tests/api/videos/video-abuse.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -183,9 +183,9 @@ describe('Test video abuses', function () { | |||
183 | const accountToBlock = 'root@localhost:' + servers[1].port | 183 | const accountToBlock = 'root@localhost:' + servers[1].port |
184 | 184 | ||
185 | { | 185 | { |
186 | await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, accountToBlock) | 186 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) |
187 | 187 | ||
188 | const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) | 188 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) |
189 | expect(res.body.total).to.equal(2) | 189 | expect(res.body.total).to.equal(2) |
190 | 190 | ||
191 | const abuse = res.body.data.find(a => a.reason === 'will mute this') | 191 | const abuse = res.body.data.find(a => a.reason === 'will mute this') |
@@ -193,9 +193,9 @@ describe('Test video abuses', function () { | |||
193 | } | 193 | } |
194 | 194 | ||
195 | { | 195 | { |
196 | await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, accountToBlock) | 196 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) |
197 | 197 | ||
198 | const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) | 198 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) |
199 | expect(res.body.total).to.equal(3) | 199 | expect(res.body.total).to.equal(3) |
200 | } | 200 | } |
201 | }) | 201 | }) |
@@ -204,9 +204,9 @@ describe('Test video abuses', function () { | |||
204 | const serverToBlock = servers[1].host | 204 | const serverToBlock = servers[1].host |
205 | 205 | ||
206 | { | 206 | { |
207 | await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, servers[1].host) | 207 | await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host) |
208 | 208 | ||
209 | const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) | 209 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) |
210 | expect(res.body.total).to.equal(2) | 210 | expect(res.body.total).to.equal(2) |
211 | 211 | ||
212 | const abuse = res.body.data.find(a => a.reason === 'will mute this') | 212 | const abuse = res.body.data.find(a => a.reason === 'will mute this') |
@@ -214,9 +214,9 @@ describe('Test video abuses', function () { | |||
214 | } | 214 | } |
215 | 215 | ||
216 | { | 216 | { |
217 | await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, serverToBlock) | 217 | await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock) |
218 | 218 | ||
219 | const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) | 219 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) |
220 | expect(res.body.total).to.equal(3) | 220 | expect(res.body.total).to.equal(3) |
221 | } | 221 | } |
222 | }) | 222 | }) |
diff --git a/server/tests/api/videos/video-blacklist.ts b/server/tests/api/videos/video-blacklist.ts index 854b2f0cb..67bc0114c 100644 --- a/server/tests/api/videos/video-blacklist.ts +++ b/server/tests/api/videos/video-blacklist.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import { orderBy } from 'lodash' | 4 | import { orderBy } from 'lodash' |
@@ -8,7 +8,8 @@ import { | |||
8 | cleanupTests, | 8 | cleanupTests, |
9 | createUser, | 9 | createUser, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
11 | getBlacklistedVideosList, getMyUserInformation, | 11 | getBlacklistedVideosList, |
12 | getMyUserInformation, | ||
12 | getMyVideos, | 13 | getMyVideos, |
13 | getVideosList, | 14 | getVideosList, |
14 | killallServers, | 15 | killallServers, |
@@ -17,7 +18,6 @@ import { | |||
17 | searchVideo, | 18 | searchVideo, |
18 | ServerInfo, | 19 | ServerInfo, |
19 | setAccessTokensToServers, | 20 | setAccessTokensToServers, |
20 | setDefaultVideoChannel, | ||
21 | updateVideo, | 21 | updateVideo, |
22 | updateVideoBlacklist, | 22 | updateVideoBlacklist, |
23 | uploadVideo, | 23 | uploadVideo, |
@@ -27,7 +27,7 @@ import { doubleFollow } from '../../../../shared/extra-utils/server/follows' | |||
27 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 27 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
28 | import { VideoBlacklist, VideoBlacklistType } from '../../../../shared/models/videos' | 28 | import { VideoBlacklist, VideoBlacklistType } from '../../../../shared/models/videos' |
29 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' | 29 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' |
30 | import { User, UserRole, UserUpdateMe } from '../../../../shared/models/users' | 30 | import { User, UserRole } from '../../../../shared/models/users' |
31 | import { getMagnetURI, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports' | 31 | import { getMagnetURI, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports' |
32 | 32 | ||
33 | const expect = chai.expect | 33 | const expect = chai.expect |
@@ -40,7 +40,7 @@ describe('Test video blacklist', function () { | |||
40 | const res = await getVideosList(server.url) | 40 | const res = await getVideosList(server.url) |
41 | 41 | ||
42 | const videos = res.body.data | 42 | const videos = res.body.data |
43 | for (let video of videos) { | 43 | for (const video of videos) { |
44 | await addVideoToBlacklist(server.url, server.accessToken, video.id, 'super reason') | 44 | await addVideoToBlacklist(server.url, server.accessToken, video.id, 'super reason') |
45 | } | 45 | } |
46 | } | 46 | } |
@@ -72,7 +72,7 @@ describe('Test video blacklist', function () { | |||
72 | 72 | ||
73 | it('Should not have the video blacklisted in videos list/search on server 1', async function () { | 73 | it('Should not have the video blacklisted in videos list/search on server 1', async function () { |
74 | { | 74 | { |
75 | const res = await getVideosList(servers[ 0 ].url) | 75 | const res = await getVideosList(servers[0].url) |
76 | 76 | ||
77 | expect(res.body.total).to.equal(0) | 77 | expect(res.body.total).to.equal(0) |
78 | expect(res.body.data).to.be.an('array') | 78 | expect(res.body.data).to.be.an('array') |
@@ -80,7 +80,7 @@ describe('Test video blacklist', function () { | |||
80 | } | 80 | } |
81 | 81 | ||
82 | { | 82 | { |
83 | const res = await searchVideo(servers[ 0 ].url, 'name') | 83 | const res = await searchVideo(servers[0].url, 'name') |
84 | 84 | ||
85 | expect(res.body.total).to.equal(0) | 85 | expect(res.body.total).to.equal(0) |
86 | expect(res.body.data).to.be.an('array') | 86 | expect(res.body.data).to.be.an('array') |
@@ -90,7 +90,7 @@ describe('Test video blacklist', function () { | |||
90 | 90 | ||
91 | it('Should have the blacklisted video in videos list/search on server 2', async function () { | 91 | it('Should have the blacklisted video in videos list/search on server 2', async function () { |
92 | { | 92 | { |
93 | const res = await getVideosList(servers[ 1 ].url) | 93 | const res = await getVideosList(servers[1].url) |
94 | 94 | ||
95 | expect(res.body.total).to.equal(2) | 95 | expect(res.body.total).to.equal(2) |
96 | expect(res.body.data).to.be.an('array') | 96 | expect(res.body.data).to.be.an('array') |
@@ -98,7 +98,7 @@ describe('Test video blacklist', function () { | |||
98 | } | 98 | } |
99 | 99 | ||
100 | { | 100 | { |
101 | const res = await searchVideo(servers[ 1 ].url, 'video') | 101 | const res = await searchVideo(servers[1].url, 'video') |
102 | 102 | ||
103 | expect(res.body.total).to.equal(2) | 103 | expect(res.body.total).to.equal(2) |
104 | expect(res.body.data).to.be.an('array') | 104 | expect(res.body.data).to.be.an('array') |
@@ -125,8 +125,8 @@ describe('Test video blacklist', function () { | |||
125 | 125 | ||
126 | it('Should display all the blacklisted videos when applying manual type filter', async function () { | 126 | it('Should display all the blacklisted videos when applying manual type filter', async function () { |
127 | const res = await getBlacklistedVideosList({ | 127 | const res = await getBlacklistedVideosList({ |
128 | url: servers[ 0 ].url, | 128 | url: servers[0].url, |
129 | token: servers[ 0 ].accessToken, | 129 | token: servers[0].accessToken, |
130 | type: VideoBlacklistType.MANUAL | 130 | type: VideoBlacklistType.MANUAL |
131 | }) | 131 | }) |
132 | 132 | ||
@@ -139,8 +139,8 @@ describe('Test video blacklist', function () { | |||
139 | 139 | ||
140 | it('Should display nothing when applying automatic type filter', async function () { | 140 | it('Should display nothing when applying automatic type filter', async function () { |
141 | const res = await getBlacklistedVideosList({ | 141 | const res = await getBlacklistedVideosList({ |
142 | url: servers[ 0 ].url, | 142 | url: servers[0].url, |
143 | token: servers[ 0 ].accessToken, | 143 | token: servers[0].accessToken, |
144 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED | 144 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED |
145 | }) | 145 | }) |
146 | 146 | ||
@@ -152,7 +152,7 @@ describe('Test video blacklist', function () { | |||
152 | }) | 152 | }) |
153 | 153 | ||
154 | it('Should get the correct sort when sorting by descending id', async function () { | 154 | it('Should get the correct sort when sorting by descending id', async function () { |
155 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-id' }) | 155 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-id' }) |
156 | expect(res.body.total).to.equal(2) | 156 | expect(res.body.total).to.equal(2) |
157 | 157 | ||
158 | const blacklistedVideos = res.body.data | 158 | const blacklistedVideos = res.body.data |
@@ -165,7 +165,7 @@ describe('Test video blacklist', function () { | |||
165 | }) | 165 | }) |
166 | 166 | ||
167 | it('Should get the correct sort when sorting by descending video name', async function () { | 167 | it('Should get the correct sort when sorting by descending video name', async function () { |
168 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) | 168 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' }) |
169 | expect(res.body.total).to.equal(2) | 169 | expect(res.body.total).to.equal(2) |
170 | 170 | ||
171 | const blacklistedVideos = res.body.data | 171 | const blacklistedVideos = res.body.data |
@@ -178,7 +178,7 @@ describe('Test video blacklist', function () { | |||
178 | }) | 178 | }) |
179 | 179 | ||
180 | it('Should get the correct sort when sorting by ascending creation date', async function () { | 180 | it('Should get the correct sort when sorting by ascending creation date', async function () { |
181 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: 'createdAt' }) | 181 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: 'createdAt' }) |
182 | expect(res.body.total).to.equal(2) | 182 | expect(res.body.total).to.equal(2) |
183 | 183 | ||
184 | const blacklistedVideos = res.body.data | 184 | const blacklistedVideos = res.body.data |
@@ -195,7 +195,7 @@ describe('Test video blacklist', function () { | |||
195 | it('Should change the reason', async function () { | 195 | it('Should change the reason', async function () { |
196 | await updateVideoBlacklist(servers[0].url, servers[0].accessToken, videoId, 'my super reason updated') | 196 | await updateVideoBlacklist(servers[0].url, servers[0].accessToken, videoId, 'my super reason updated') |
197 | 197 | ||
198 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) | 198 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' }) |
199 | const video = res.body.data.find(b => b.video.id === videoId) | 199 | const video = res.body.data.find(b => b.video.id === videoId) |
200 | 200 | ||
201 | expect(video.reason).to.equal('my super reason updated') | 201 | expect(video.reason).to.equal('my super reason updated') |
@@ -231,7 +231,7 @@ describe('Test video blacklist', function () { | |||
231 | 231 | ||
232 | it('Should remove a video from the blacklist on server 1', async function () { | 232 | it('Should remove a video from the blacklist on server 1', async function () { |
233 | // Get one video in the blacklist | 233 | // Get one video in the blacklist |
234 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) | 234 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' }) |
235 | videoToRemove = res.body.data[0] | 235 | videoToRemove = res.body.data[0] |
236 | blacklist = res.body.data.slice(1) | 236 | blacklist = res.body.data.slice(1) |
237 | 237 | ||
@@ -252,7 +252,7 @@ describe('Test video blacklist', function () { | |||
252 | }) | 252 | }) |
253 | 253 | ||
254 | it('Should not have the ex-blacklisted video in videos blacklist list on server 1', async function () { | 254 | it('Should not have the ex-blacklisted video in videos blacklist list on server 1', async function () { |
255 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) | 255 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' }) |
256 | expect(res.body.total).to.equal(1) | 256 | expect(res.body.total).to.equal(1) |
257 | 257 | ||
258 | const videos = res.body.data | 258 | const videos = res.body.data |
@@ -274,7 +274,7 @@ describe('Test video blacklist', function () { | |||
274 | video3UUID = res.body.video.uuid | 274 | video3UUID = res.body.video.uuid |
275 | } | 275 | } |
276 | { | 276 | { |
277 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'Video 4' }) | 277 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'Video 4' }) |
278 | video4UUID = res.body.video.uuid | 278 | video4UUID = res.body.video.uuid |
279 | } | 279 | } |
280 | 280 | ||
@@ -284,17 +284,17 @@ describe('Test video blacklist', function () { | |||
284 | it('Should blacklist video 3 and keep it federated', async function () { | 284 | it('Should blacklist video 3 and keep it federated', async function () { |
285 | this.timeout(10000) | 285 | this.timeout(10000) |
286 | 286 | ||
287 | await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video3UUID, 'super reason', false) | 287 | await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video3UUID, 'super reason', false) |
288 | 288 | ||
289 | await waitJobs(servers) | 289 | await waitJobs(servers) |
290 | 290 | ||
291 | { | 291 | { |
292 | const res = await getVideosList(servers[ 0 ].url) | 292 | const res = await getVideosList(servers[0].url) |
293 | expect(res.body.data.find(v => v.uuid === video3UUID)).to.be.undefined | 293 | expect(res.body.data.find(v => v.uuid === video3UUID)).to.be.undefined |
294 | } | 294 | } |
295 | 295 | ||
296 | { | 296 | { |
297 | const res = await getVideosList(servers[ 1 ].url) | 297 | const res = await getVideosList(servers[1].url) |
298 | expect(res.body.data.find(v => v.uuid === video3UUID)).to.not.be.undefined | 298 | expect(res.body.data.find(v => v.uuid === video3UUID)).to.not.be.undefined |
299 | } | 299 | } |
300 | }) | 300 | }) |
@@ -302,7 +302,7 @@ describe('Test video blacklist', function () { | |||
302 | it('Should unfederate the video', async function () { | 302 | it('Should unfederate the video', async function () { |
303 | this.timeout(10000) | 303 | this.timeout(10000) |
304 | 304 | ||
305 | await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID, 'super reason', true) | 305 | await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video4UUID, 'super reason', true) |
306 | 306 | ||
307 | await waitJobs(servers) | 307 | await waitJobs(servers) |
308 | 308 | ||
@@ -315,7 +315,7 @@ describe('Test video blacklist', function () { | |||
315 | it('Should have the video unfederated even after an Update AP message', async function () { | 315 | it('Should have the video unfederated even after an Update AP message', async function () { |
316 | this.timeout(10000) | 316 | this.timeout(10000) |
317 | 317 | ||
318 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID, { description: 'super description' }) | 318 | await updateVideo(servers[0].url, servers[0].accessToken, video4UUID, { description: 'super description' }) |
319 | 319 | ||
320 | await waitJobs(servers) | 320 | await waitJobs(servers) |
321 | 321 | ||
@@ -326,7 +326,7 @@ describe('Test video blacklist', function () { | |||
326 | }) | 326 | }) |
327 | 327 | ||
328 | it('Should have the correct video blacklist unfederate attribute', async function () { | 328 | it('Should have the correct video blacklist unfederate attribute', async function () { |
329 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: 'createdAt' }) | 329 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: 'createdAt' }) |
330 | 330 | ||
331 | const blacklistedVideos: VideoBlacklist[] = res.body.data | 331 | const blacklistedVideos: VideoBlacklist[] = res.body.data |
332 | const video3Blacklisted = blacklistedVideos.find(b => b.video.uuid === video3UUID) | 332 | const video3Blacklisted = blacklistedVideos.find(b => b.video.uuid === video3UUID) |
@@ -339,7 +339,7 @@ describe('Test video blacklist', function () { | |||
339 | it('Should remove the video from blacklist and refederate the video', async function () { | 339 | it('Should remove the video from blacklist and refederate the video', async function () { |
340 | this.timeout(10000) | 340 | this.timeout(10000) |
341 | 341 | ||
342 | await removeVideoFromBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID) | 342 | await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, video4UUID) |
343 | 343 | ||
344 | await waitJobs(servers) | 344 | await waitJobs(servers) |
345 | 345 | ||
@@ -362,9 +362,9 @@ describe('Test video blacklist', function () { | |||
362 | killallServers([ servers[0] ]) | 362 | killallServers([ servers[0] ]) |
363 | 363 | ||
364 | const config = { | 364 | const config = { |
365 | 'auto_blacklist': { | 365 | auto_blacklist: { |
366 | videos: { | 366 | videos: { |
367 | 'of_users': { | 367 | of_users: { |
368 | enabled: true | 368 | enabled: true |
369 | } | 369 | } |
370 | } | 370 | } |
@@ -375,8 +375,8 @@ describe('Test video blacklist', function () { | |||
375 | { | 375 | { |
376 | const user = { username: 'user_without_flag', password: 'password' } | 376 | const user = { username: 'user_without_flag', password: 'password' } |
377 | await createUser({ | 377 | await createUser({ |
378 | url: servers[ 0 ].url, | 378 | url: servers[0].url, |
379 | accessToken: servers[ 0 ].accessToken, | 379 | accessToken: servers[0].accessToken, |
380 | username: user.username, | 380 | username: user.username, |
381 | adminFlags: UserAdminFlag.NONE, | 381 | adminFlags: UserAdminFlag.NONE, |
382 | password: user.password, | 382 | password: user.password, |
@@ -393,8 +393,8 @@ describe('Test video blacklist', function () { | |||
393 | { | 393 | { |
394 | const user = { username: 'user_with_flag', password: 'password' } | 394 | const user = { username: 'user_with_flag', password: 'password' } |
395 | await createUser({ | 395 | await createUser({ |
396 | url: servers[ 0 ].url, | 396 | url: servers[0].url, |
397 | accessToken: servers[ 0 ].accessToken, | 397 | accessToken: servers[0].accessToken, |
398 | username: user.username, | 398 | username: user.username, |
399 | adminFlags: UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST, | 399 | adminFlags: UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST, |
400 | password: user.password, | 400 | password: user.password, |
@@ -411,8 +411,8 @@ describe('Test video blacklist', function () { | |||
411 | await uploadVideo(servers[0].url, userWithoutFlag, { name: 'blacklisted' }) | 411 | await uploadVideo(servers[0].url, userWithoutFlag, { name: 'blacklisted' }) |
412 | 412 | ||
413 | const res = await getBlacklistedVideosList({ | 413 | const res = await getBlacklistedVideosList({ |
414 | url: servers[ 0 ].url, | 414 | url: servers[0].url, |
415 | token: servers[ 0 ].accessToken, | 415 | token: servers[0].accessToken, |
416 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED | 416 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED |
417 | }) | 417 | }) |
418 | 418 | ||
@@ -428,11 +428,11 @@ describe('Test video blacklist', function () { | |||
428 | name: 'URL import', | 428 | name: 'URL import', |
429 | channelId: channelOfUserWithoutFlag | 429 | channelId: channelOfUserWithoutFlag |
430 | } | 430 | } |
431 | await importVideo(servers[ 0 ].url, userWithoutFlag, attributes) | 431 | await importVideo(servers[0].url, userWithoutFlag, attributes) |
432 | 432 | ||
433 | const res = await getBlacklistedVideosList({ | 433 | const res = await getBlacklistedVideosList({ |
434 | url: servers[ 0 ].url, | 434 | url: servers[0].url, |
435 | token: servers[ 0 ].accessToken, | 435 | token: servers[0].accessToken, |
436 | sort: 'createdAt', | 436 | sort: 'createdAt', |
437 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED | 437 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED |
438 | }) | 438 | }) |
@@ -447,11 +447,11 @@ describe('Test video blacklist', function () { | |||
447 | name: 'Torrent import', | 447 | name: 'Torrent import', |
448 | channelId: channelOfUserWithoutFlag | 448 | channelId: channelOfUserWithoutFlag |
449 | } | 449 | } |
450 | await importVideo(servers[ 0 ].url, userWithoutFlag, attributes) | 450 | await importVideo(servers[0].url, userWithoutFlag, attributes) |
451 | 451 | ||
452 | const res = await getBlacklistedVideosList({ | 452 | const res = await getBlacklistedVideosList({ |
453 | url: servers[ 0 ].url, | 453 | url: servers[0].url, |
454 | token: servers[ 0 ].accessToken, | 454 | token: servers[0].accessToken, |
455 | sort: 'createdAt', | 455 | sort: 'createdAt', |
456 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED | 456 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED |
457 | }) | 457 | }) |
@@ -464,8 +464,8 @@ describe('Test video blacklist', function () { | |||
464 | await uploadVideo(servers[0].url, userWithFlag, { name: 'not blacklisted' }) | 464 | await uploadVideo(servers[0].url, userWithFlag, { name: 'not blacklisted' }) |
465 | 465 | ||
466 | const res = await getBlacklistedVideosList({ | 466 | const res = await getBlacklistedVideosList({ |
467 | url: servers[ 0 ].url, | 467 | url: servers[0].url, |
468 | token: servers[ 0 ].accessToken, | 468 | token: servers[0].accessToken, |
469 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED | 469 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED |
470 | }) | 470 | }) |
471 | 471 | ||
diff --git a/server/tests/api/videos/video-captions.ts b/server/tests/api/videos/video-captions.ts index 5e13f5949..b4ecb39f4 100644 --- a/server/tests/api/videos/video-captions.ts +++ b/server/tests/api/videos/video-captions.ts | |||
@@ -1,16 +1,17 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | checkVideoFilesWereRemoved, cleanupTests, | 6 | checkVideoFilesWereRemoved, |
7 | cleanupTests, | ||
7 | doubleFollow, | 8 | doubleFollow, |
8 | flushAndRunMultipleServers, | 9 | flushAndRunMultipleServers, |
9 | removeVideo, | 10 | removeVideo, |
10 | uploadVideo, | 11 | uploadVideo, |
11 | wait | 12 | wait |
12 | } from '../../../../shared/extra-utils' | 13 | } from '../../../../shared/extra-utils' |
13 | import { flushTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index' | 14 | import { ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index' |
14 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 15 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
15 | import { | 16 | import { |
16 | createVideoCaption, | 17 | createVideoCaption, |
@@ -36,7 +37,7 @@ describe('Test video captions', function () { | |||
36 | 37 | ||
37 | await waitJobs(servers) | 38 | await waitJobs(servers) |
38 | 39 | ||
39 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'my video name' }) | 40 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'my video name' }) |
40 | videoUUID = res.body.video.uuid | 41 | videoUUID = res.body.video.uuid |
41 | 42 | ||
42 | await waitJobs(servers) | 43 | await waitJobs(servers) |
diff --git a/server/tests/api/videos/video-change-ownership.ts b/server/tests/api/videos/video-change-ownership.ts index 64ee2355a..dee6575b9 100644 --- a/server/tests/api/videos/video-change-ownership.ts +++ b/server/tests/api/videos/video-change-ownership.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -38,7 +38,7 @@ describe('Test video change ownership - nominal', function () { | |||
38 | } | 38 | } |
39 | let firstUserAccessToken = '' | 39 | let firstUserAccessToken = '' |
40 | let secondUserAccessToken = '' | 40 | let secondUserAccessToken = '' |
41 | let lastRequestChangeOwnershipId = undefined | 41 | let lastRequestChangeOwnershipId = '' |
42 | 42 | ||
43 | before(async function () { | 43 | before(async function () { |
44 | this.timeout(50000) | 44 | this.timeout(50000) |
@@ -48,15 +48,15 @@ describe('Test video change ownership - nominal', function () { | |||
48 | 48 | ||
49 | const videoQuota = 42000000 | 49 | const videoQuota = 42000000 |
50 | await createUser({ | 50 | await createUser({ |
51 | url: servers[ 0 ].url, | 51 | url: servers[0].url, |
52 | accessToken: servers[ 0 ].accessToken, | 52 | accessToken: servers[0].accessToken, |
53 | username: firstUser.username, | 53 | username: firstUser.username, |
54 | password: firstUser.password, | 54 | password: firstUser.password, |
55 | videoQuota: videoQuota | 55 | videoQuota: videoQuota |
56 | }) | 56 | }) |
57 | await createUser({ | 57 | await createUser({ |
58 | url: servers[ 0 ].url, | 58 | url: servers[0].url, |
59 | accessToken: servers[ 0 ].accessToken, | 59 | accessToken: servers[0].accessToken, |
60 | username: secondUser.username, | 60 | username: secondUser.username, |
61 | password: secondUser.password, | 61 | password: secondUser.password, |
62 | videoQuota: videoQuota | 62 | videoQuota: videoQuota |
@@ -209,7 +209,7 @@ describe('Test video change ownership - nominal', function () { | |||
209 | }) | 209 | }) |
210 | 210 | ||
211 | describe('Test video change ownership - quota too small', function () { | 211 | describe('Test video change ownership - quota too small', function () { |
212 | let server: ServerInfo = undefined | 212 | let server: ServerInfo |
213 | const firstUser = { | 213 | const firstUser = { |
214 | username: 'first', | 214 | username: 'first', |
215 | password: 'My great password' | 215 | password: 'My great password' |
@@ -220,14 +220,14 @@ describe('Test video change ownership - quota too small', function () { | |||
220 | } | 220 | } |
221 | let firstUserAccessToken = '' | 221 | let firstUserAccessToken = '' |
222 | let secondUserAccessToken = '' | 222 | let secondUserAccessToken = '' |
223 | let lastRequestChangeOwnershipId = undefined | 223 | let lastRequestChangeOwnershipId = '' |
224 | 224 | ||
225 | before(async function () { | 225 | before(async function () { |
226 | this.timeout(50000) | 226 | this.timeout(50000) |
227 | 227 | ||
228 | // Run one server | 228 | // Run one server |
229 | server = await flushAndRunServer(1) | 229 | server = await flushAndRunServer(1) |
230 | await setAccessTokensToServers([server]) | 230 | await setAccessTokensToServers([ server ]) |
231 | 231 | ||
232 | const videoQuota = 42000000 | 232 | const videoQuota = 42000000 |
233 | const limitedVideoQuota = 10 | 233 | const limitedVideoQuota = 10 |
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts index 4f600cae8..f3a23bf17 100644 --- a/server/tests/api/videos/video-channels.ts +++ b/server/tests/api/videos/video-channels.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -7,7 +7,8 @@ import { | |||
7 | cleanupTests, | 7 | cleanupTests, |
8 | createUser, | 8 | createUser, |
9 | doubleFollow, | 9 | doubleFollow, |
10 | flushAndRunMultipleServers, getVideo, | 10 | flushAndRunMultipleServers, |
11 | getVideo, | ||
11 | getVideoChannelVideos, | 12 | getVideoChannelVideos, |
12 | testImage, | 13 | testImage, |
13 | updateVideo, | 14 | updateVideo, |
@@ -73,14 +74,14 @@ describe('Test video channels', function () { | |||
73 | description: 'super video channel description', | 74 | description: 'super video channel description', |
74 | support: 'super video channel support text' | 75 | support: 'super video channel support text' |
75 | } | 76 | } |
76 | const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel) | 77 | const res = await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel) |
77 | secondVideoChannelId = res.body.videoChannel.id | 78 | secondVideoChannelId = res.body.videoChannel.id |
78 | } | 79 | } |
79 | 80 | ||
80 | // The channel is 1 is propagated to servers 2 | 81 | // The channel is 1 is propagated to servers 2 |
81 | { | 82 | { |
82 | const videoAttributesArg = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' } | 83 | const videoAttributesArg = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' } |
83 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributesArg) | 84 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributesArg) |
84 | videoUUID = res.body.video.uuid | 85 | videoUUID = res.body.video.uuid |
85 | } | 86 | } |
86 | 87 | ||
@@ -106,7 +107,7 @@ describe('Test video channels', function () { | |||
106 | 107 | ||
107 | it('Should have two video channels when getting account channels on server 1', async function () { | 108 | it('Should have two video channels when getting account channels on server 1', async function () { |
108 | const res = await getAccountVideoChannelsList({ | 109 | const res = await getAccountVideoChannelsList({ |
109 | url: servers[ 0 ].url, | 110 | url: servers[0].url, |
110 | accountName: userInfo.account.name + '@' + userInfo.account.host | 111 | accountName: userInfo.account.name + '@' + userInfo.account.host |
111 | }) | 112 | }) |
112 | 113 | ||
@@ -127,7 +128,7 @@ describe('Test video channels', function () { | |||
127 | it('Should paginate and sort account channels', async function () { | 128 | it('Should paginate and sort account channels', async function () { |
128 | { | 129 | { |
129 | const res = await getAccountVideoChannelsList({ | 130 | const res = await getAccountVideoChannelsList({ |
130 | url: servers[ 0 ].url, | 131 | url: servers[0].url, |
131 | accountName: userInfo.account.name + '@' + userInfo.account.host, | 132 | accountName: userInfo.account.name + '@' + userInfo.account.host, |
132 | start: 0, | 133 | start: 0, |
133 | count: 1, | 134 | count: 1, |
@@ -137,13 +138,13 @@ describe('Test video channels', function () { | |||
137 | expect(res.body.total).to.equal(2) | 138 | expect(res.body.total).to.equal(2) |
138 | expect(res.body.data).to.have.lengthOf(1) | 139 | expect(res.body.data).to.have.lengthOf(1) |
139 | 140 | ||
140 | const videoChannel: VideoChannel = res.body.data[ 0 ] | 141 | const videoChannel: VideoChannel = res.body.data[0] |
141 | expect(videoChannel.name).to.equal('root_channel') | 142 | expect(videoChannel.name).to.equal('root_channel') |
142 | } | 143 | } |
143 | 144 | ||
144 | { | 145 | { |
145 | const res = await getAccountVideoChannelsList({ | 146 | const res = await getAccountVideoChannelsList({ |
146 | url: servers[ 0 ].url, | 147 | url: servers[0].url, |
147 | accountName: userInfo.account.name + '@' + userInfo.account.host, | 148 | accountName: userInfo.account.name + '@' + userInfo.account.host, |
148 | start: 0, | 149 | start: 0, |
149 | count: 1, | 150 | count: 1, |
@@ -153,13 +154,13 @@ describe('Test video channels', function () { | |||
153 | expect(res.body.total).to.equal(2) | 154 | expect(res.body.total).to.equal(2) |
154 | expect(res.body.data).to.have.lengthOf(1) | 155 | expect(res.body.data).to.have.lengthOf(1) |
155 | 156 | ||
156 | const videoChannel: VideoChannel = res.body.data[ 0 ] | 157 | const videoChannel: VideoChannel = res.body.data[0] |
157 | expect(videoChannel.name).to.equal('second_video_channel') | 158 | expect(videoChannel.name).to.equal('second_video_channel') |
158 | } | 159 | } |
159 | 160 | ||
160 | { | 161 | { |
161 | const res = await getAccountVideoChannelsList({ | 162 | const res = await getAccountVideoChannelsList({ |
162 | url: servers[ 0 ].url, | 163 | url: servers[0].url, |
163 | accountName: userInfo.account.name + '@' + userInfo.account.host, | 164 | accountName: userInfo.account.name + '@' + userInfo.account.host, |
164 | start: 1, | 165 | start: 1, |
165 | count: 1, | 166 | count: 1, |
@@ -169,14 +170,14 @@ describe('Test video channels', function () { | |||
169 | expect(res.body.total).to.equal(2) | 170 | expect(res.body.total).to.equal(2) |
170 | expect(res.body.data).to.have.lengthOf(1) | 171 | expect(res.body.data).to.have.lengthOf(1) |
171 | 172 | ||
172 | const videoChannel: VideoChannel = res.body.data[ 0 ] | 173 | const videoChannel: VideoChannel = res.body.data[0] |
173 | expect(videoChannel.name).to.equal('root_channel') | 174 | expect(videoChannel.name).to.equal('root_channel') |
174 | } | 175 | } |
175 | }) | 176 | }) |
176 | 177 | ||
177 | it('Should have one video channel when getting account channels on server 2', async function () { | 178 | it('Should have one video channel when getting account channels on server 2', async function () { |
178 | const res = await getAccountVideoChannelsList({ | 179 | const res = await getAccountVideoChannelsList({ |
179 | url: servers[ 1 ].url, | 180 | url: servers[1].url, |
180 | accountName: userInfo.account.name + '@' + userInfo.account.host | 181 | accountName: userInfo.account.name + '@' + userInfo.account.host |
181 | }) | 182 | }) |
182 | 183 | ||
@@ -349,15 +350,15 @@ describe('Test video channels', function () { | |||
349 | it('Should create the main channel with an uuid if there is a conflict', async function () { | 350 | it('Should create the main channel with an uuid if there is a conflict', async function () { |
350 | { | 351 | { |
351 | const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' } | 352 | const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' } |
352 | await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel) | 353 | await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel) |
353 | } | 354 | } |
354 | 355 | ||
355 | { | 356 | { |
356 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: 'toto', password: 'password' }) | 357 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: 'toto', password: 'password' }) |
357 | const accessToken = await userLogin(servers[ 0 ], { username: 'toto', password: 'password' }) | 358 | const accessToken = await userLogin(servers[0], { username: 'toto', password: 'password' }) |
358 | 359 | ||
359 | const res = await getMyUserInformation(servers[ 0 ].url, accessToken) | 360 | const res = await getMyUserInformation(servers[0].url, accessToken) |
360 | const videoChannel = res.body.videoChannels[ 0 ] | 361 | const videoChannel = res.body.videoChannels[0] |
361 | expect(videoChannel.name).to.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/) | 362 | expect(videoChannel.name).to.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/) |
362 | } | 363 | } |
363 | }) | 364 | }) |
diff --git a/server/tests/api/videos/video-comments.ts b/server/tests/api/videos/video-comments.ts index 06e4ff9c8..afb58e95a 100644 --- a/server/tests/api/videos/video-comments.ts +++ b/server/tests/api/videos/video-comments.ts | |||
@@ -1,17 +1,17 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' | 5 | import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' |
6 | import { cleanupTests, testImage } from '../../../../shared/extra-utils' | 6 | import { cleanupTests, testImage } from '../../../../shared/extra-utils' |
7 | import { | 7 | import { |
8 | createUser, | ||
8 | dateIsValid, | 9 | dateIsValid, |
9 | flushAndRunServer, | 10 | flushAndRunServer, |
11 | getAccessToken, | ||
10 | ServerInfo, | 12 | ServerInfo, |
11 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
12 | updateMyAvatar, | 14 | updateMyAvatar, |
13 | getAccessToken, | ||
14 | createUser, | ||
15 | uploadVideo | 15 | uploadVideo |
16 | } from '../../../../shared/extra-utils/index' | 16 | } from '../../../../shared/extra-utils/index' |
17 | import { | 17 | import { |
diff --git a/server/tests/api/videos/video-description.ts b/server/tests/api/videos/video-description.ts index db4d278bf..b8e98e45f 100644 --- a/server/tests/api/videos/video-description.ts +++ b/server/tests/api/videos/video-description.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -8,7 +8,6 @@ import { | |||
8 | getVideo, | 8 | getVideo, |
9 | getVideoDescription, | 9 | getVideoDescription, |
10 | getVideosList, | 10 | getVideosList, |
11 | killallServers, | ||
12 | ServerInfo, | 11 | ServerInfo, |
13 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
14 | updateVideo, | 13 | updateVideo, |
@@ -23,7 +22,7 @@ describe('Test video description', function () { | |||
23 | let servers: ServerInfo[] = [] | 22 | let servers: ServerInfo[] = [] |
24 | let videoUUID = '' | 23 | let videoUUID = '' |
25 | let videoId: number | 24 | let videoId: number |
26 | let longDescription = 'my super description for server 1'.repeat(50) | 25 | const longDescription = 'my super description for server 1'.repeat(50) |
27 | 26 | ||
28 | before(async function () { | 27 | before(async function () { |
29 | this.timeout(40000) | 28 | this.timeout(40000) |
@@ -61,7 +60,7 @@ describe('Test video description', function () { | |||
61 | 60 | ||
62 | // 30 characters * 6 -> 240 characters | 61 | // 30 characters * 6 -> 240 characters |
63 | const truncatedDescription = 'my super description for server 1'.repeat(7) + | 62 | const truncatedDescription = 'my super description for server 1'.repeat(7) + |
64 | 'my super descrip...' | 63 | 'my super descrip...' |
65 | 64 | ||
66 | expect(video.description).to.equal(truncatedDescription) | 65 | expect(video.description).to.equal(truncatedDescription) |
67 | } | 66 | } |
diff --git a/server/tests/api/videos/video-hls.ts b/server/tests/api/videos/video-hls.ts index bde3b5656..6555bc8b6 100644 --- a/server/tests/api/videos/video-hls.ts +++ b/server/tests/api/videos/video-hls.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -10,13 +10,16 @@ import { | |||
10 | doubleFollow, | 10 | doubleFollow, |
11 | flushAndRunMultipleServers, | 11 | flushAndRunMultipleServers, |
12 | getPlaylist, | 12 | getPlaylist, |
13 | getVideo, makeGetRequest, makeRawRequest, | 13 | getVideo, |
14 | makeRawRequest, | ||
14 | removeVideo, | 15 | removeVideo, |
15 | ServerInfo, | 16 | ServerInfo, |
16 | setAccessTokensToServers, updateCustomSubConfig, | 17 | setAccessTokensToServers, |
18 | updateCustomSubConfig, | ||
17 | updateVideo, | 19 | updateVideo, |
18 | uploadVideo, | 20 | uploadVideo, |
19 | waitJobs, webtorrentAdd | 21 | waitJobs, |
22 | webtorrentAdd | ||
20 | } from '../../../../shared/extra-utils' | 23 | } from '../../../../shared/extra-utils' |
21 | import { VideoDetails } from '../../../../shared/models/videos' | 24 | import { VideoDetails } from '../../../../shared/models/videos' |
22 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' | 25 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' |
@@ -48,7 +51,9 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, hlsOn | |||
48 | 51 | ||
49 | expect(file.magnetUri).to.have.lengthOf.above(2) | 52 | expect(file.magnetUri).to.have.lengthOf.above(2) |
50 | expect(file.torrentUrl).to.equal(`${baseUrl}/static/torrents/${videoDetails.uuid}-${file.resolution.id}-hls.torrent`) | 53 | expect(file.torrentUrl).to.equal(`${baseUrl}/static/torrents/${videoDetails.uuid}-${file.resolution.id}-hls.torrent`) |
51 | expect(file.fileUrl).to.equal(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${videoDetails.uuid}-${file.resolution.id}-fragmented.mp4`) | 54 | expect(file.fileUrl).to.equal( |
55 | `${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${videoDetails.uuid}-${file.resolution.id}-fragmented.mp4` | ||
56 | ) | ||
52 | expect(file.resolution.label).to.equal(resolution + 'p') | 57 | expect(file.resolution.label).to.equal(resolution + 'p') |
53 | 58 | ||
54 | await makeRawRequest(file.torrentUrl, 200) | 59 | await makeRawRequest(file.torrentUrl, 200) |
@@ -66,7 +71,9 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, hlsOn | |||
66 | const masterPlaylist = res.text | 71 | const masterPlaylist = res.text |
67 | 72 | ||
68 | for (const resolution of resolutions) { | 73 | for (const resolution of resolutions) { |
69 | const reg = new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+,CODECS="avc1.64001f,mp4a.40.2"') | 74 | const reg = new RegExp( |
75 | '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+,CODECS="avc1.64001f,mp4a.40.2"' | ||
76 | ) | ||
70 | 77 | ||
71 | expect(masterPlaylist).to.match(reg) | 78 | expect(masterPlaylist).to.match(reg) |
72 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) | 79 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) |
@@ -102,7 +109,7 @@ describe('Test HLS videos', function () { | |||
102 | it('Should upload a video and transcode it to HLS', async function () { | 109 | it('Should upload a video and transcode it to HLS', async function () { |
103 | this.timeout(120000) | 110 | this.timeout(120000) |
104 | 111 | ||
105 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' }) | 112 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 1', fixture: 'video_short.webm' }) |
106 | videoUUID = res.body.video.uuid | 113 | videoUUID = res.body.video.uuid |
107 | 114 | ||
108 | await waitJobs(servers) | 115 | await waitJobs(servers) |
@@ -113,7 +120,7 @@ describe('Test HLS videos', function () { | |||
113 | it('Should upload an audio file and transcode it to HLS', async function () { | 120 | it('Should upload an audio file and transcode it to HLS', async function () { |
114 | this.timeout(120000) | 121 | this.timeout(120000) |
115 | 122 | ||
116 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video audio', fixture: 'sample.ogg' }) | 123 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video audio', fixture: 'sample.ogg' }) |
117 | videoAudioUUID = res.body.video.uuid | 124 | videoAudioUUID = res.body.video.uuid |
118 | 125 | ||
119 | await waitJobs(servers) | 126 | await waitJobs(servers) |
@@ -124,7 +131,7 @@ describe('Test HLS videos', function () { | |||
124 | it('Should update the video', async function () { | 131 | it('Should update the video', async function () { |
125 | this.timeout(10000) | 132 | this.timeout(10000) |
126 | 133 | ||
127 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, { name: 'video 1 updated' }) | 134 | await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video 1 updated' }) |
128 | 135 | ||
129 | await waitJobs(servers) | 136 | await waitJobs(servers) |
130 | 137 | ||
@@ -134,8 +141,8 @@ describe('Test HLS videos', function () { | |||
134 | it('Should delete videos', async function () { | 141 | it('Should delete videos', async function () { |
135 | this.timeout(10000) | 142 | this.timeout(10000) |
136 | 143 | ||
137 | await removeVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID) | 144 | await removeVideo(servers[0].url, servers[0].accessToken, videoUUID) |
138 | await removeVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAudioUUID) | 145 | await removeVideo(servers[0].url, servers[0].accessToken, videoAudioUUID) |
139 | 146 | ||
140 | await waitJobs(servers) | 147 | await waitJobs(servers) |
141 | 148 | ||
diff --git a/server/tests/api/videos/video-imports.ts b/server/tests/api/videos/video-imports.ts index 1233ed6eb..a67e528c6 100644 --- a/server/tests/api/videos/video-imports.ts +++ b/server/tests/api/videos/video-imports.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -12,12 +12,11 @@ import { | |||
12 | getVideo, | 12 | getVideo, |
13 | getVideosList, | 13 | getVideosList, |
14 | immutableAssign, | 14 | immutableAssign, |
15 | killallServers, | ||
16 | ServerInfo, | 15 | ServerInfo, |
17 | setAccessTokensToServers | 16 | setAccessTokensToServers |
18 | } from '../../../../shared/extra-utils' | 17 | } from '../../../../shared/extra-utils' |
19 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 18 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
20 | import { getMagnetURI, getYoutubeVideoUrl, importVideo, getMyVideoImports } from '../../../../shared/extra-utils/videos/video-imports' | 19 | import { getMagnetURI, getMyVideoImports, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports' |
21 | 20 | ||
22 | const expect = chai.expect | 21 | const expect = chai.expect |
23 | 22 | ||
@@ -88,12 +87,12 @@ describe('Test video imports', function () { | |||
88 | 87 | ||
89 | { | 88 | { |
90 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) | 89 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) |
91 | channelIdServer1 = res.body.videoChannels[ 0 ].id | 90 | channelIdServer1 = res.body.videoChannels[0].id |
92 | } | 91 | } |
93 | 92 | ||
94 | { | 93 | { |
95 | const res = await getMyUserInformation(servers[1].url, servers[1].accessToken) | 94 | const res = await getMyUserInformation(servers[1].url, servers[1].accessToken) |
96 | channelIdServer2 = res.body.videoChannels[ 0 ].id | 95 | channelIdServer2 = res.body.videoChannels[0].id |
97 | } | 96 | } |
98 | 97 | ||
99 | await doubleFollow(servers[0], servers[1]) | 98 | await doubleFollow(servers[0], servers[1]) |
@@ -214,7 +213,7 @@ describe('Test video imports', function () { | |||
214 | 213 | ||
215 | await checkVideoServer2(server.url, res.body.data[0].uuid) | 214 | await checkVideoServer2(server.url, res.body.data[0].uuid) |
216 | 215 | ||
217 | const [ ,videoHttp, videoMagnet, videoTorrent ] = res.body.data | 216 | const [ , videoHttp, videoMagnet, videoTorrent ] = res.body.data |
218 | await checkVideosServer1(server.url, videoHttp.uuid, videoMagnet.uuid, videoTorrent.uuid) | 217 | await checkVideosServer1(server.url, videoHttp.uuid, videoMagnet.uuid, videoTorrent.uuid) |
219 | } | 218 | } |
220 | }) | 219 | }) |
diff --git a/server/tests/api/videos/video-nsfw.ts b/server/tests/api/videos/video-nsfw.ts index ad6a4b43f..7eba8d7d9 100644 --- a/server/tests/api/videos/video-nsfw.ts +++ b/server/tests/api/videos/video-nsfw.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -89,8 +89,8 @@ describe('Test video NSFW policy', function () { | |||
89 | 89 | ||
90 | const videos = res.body.data | 90 | const videos = res.body.data |
91 | expect(videos).to.have.lengthOf(2) | 91 | expect(videos).to.have.lengthOf(2) |
92 | expect(videos[ 0 ].name).to.equal('normal') | 92 | expect(videos[0].name).to.equal('normal') |
93 | expect(videos[ 1 ].name).to.equal('nsfw') | 93 | expect(videos[1].name).to.equal('nsfw') |
94 | } | 94 | } |
95 | }) | 95 | }) |
96 | 96 | ||
@@ -107,7 +107,7 @@ describe('Test video NSFW policy', function () { | |||
107 | 107 | ||
108 | const videos = res.body.data | 108 | const videos = res.body.data |
109 | expect(videos).to.have.lengthOf(1) | 109 | expect(videos).to.have.lengthOf(1) |
110 | expect(videos[ 0 ].name).to.equal('normal') | 110 | expect(videos[0].name).to.equal('normal') |
111 | } | 111 | } |
112 | }) | 112 | }) |
113 | 113 | ||
@@ -124,8 +124,8 @@ describe('Test video NSFW policy', function () { | |||
124 | 124 | ||
125 | const videos = res.body.data | 125 | const videos = res.body.data |
126 | expect(videos).to.have.lengthOf(2) | 126 | expect(videos).to.have.lengthOf(2) |
127 | expect(videos[ 0 ].name).to.equal('normal') | 127 | expect(videos[0].name).to.equal('normal') |
128 | expect(videos[ 1 ].name).to.equal('nsfw') | 128 | expect(videos[1].name).to.equal('nsfw') |
129 | } | 129 | } |
130 | }) | 130 | }) |
131 | }) | 131 | }) |
@@ -154,8 +154,8 @@ describe('Test video NSFW policy', function () { | |||
154 | 154 | ||
155 | const videos = res.body.data | 155 | const videos = res.body.data |
156 | expect(videos).to.have.lengthOf(2) | 156 | expect(videos).to.have.lengthOf(2) |
157 | expect(videos[ 0 ].name).to.equal('normal') | 157 | expect(videos[0].name).to.equal('normal') |
158 | expect(videos[ 1 ].name).to.equal('nsfw') | 158 | expect(videos[1].name).to.equal('nsfw') |
159 | } | 159 | } |
160 | }) | 160 | }) |
161 | 161 | ||
@@ -171,8 +171,8 @@ describe('Test video NSFW policy', function () { | |||
171 | 171 | ||
172 | const videos = res.body.data | 172 | const videos = res.body.data |
173 | expect(videos).to.have.lengthOf(2) | 173 | expect(videos).to.have.lengthOf(2) |
174 | expect(videos[ 0 ].name).to.equal('normal') | 174 | expect(videos[0].name).to.equal('normal') |
175 | expect(videos[ 1 ].name).to.equal('nsfw') | 175 | expect(videos[1].name).to.equal('nsfw') |
176 | } | 176 | } |
177 | }) | 177 | }) |
178 | 178 | ||
@@ -188,7 +188,7 @@ describe('Test video NSFW policy', function () { | |||
188 | 188 | ||
189 | const videos = res.body.data | 189 | const videos = res.body.data |
190 | expect(videos).to.have.lengthOf(1) | 190 | expect(videos).to.have.lengthOf(1) |
191 | expect(videos[ 0 ].name).to.equal('normal') | 191 | expect(videos[0].name).to.equal('normal') |
192 | } | 192 | } |
193 | }) | 193 | }) |
194 | 194 | ||
@@ -198,8 +198,8 @@ describe('Test video NSFW policy', function () { | |||
198 | 198 | ||
199 | const videos = res.body.data | 199 | const videos = res.body.data |
200 | expect(videos).to.have.lengthOf(2) | 200 | expect(videos).to.have.lengthOf(2) |
201 | expect(videos[ 0 ].name).to.equal('normal') | 201 | expect(videos[0].name).to.equal('normal') |
202 | expect(videos[ 1 ].name).to.equal('nsfw') | 202 | expect(videos[1].name).to.equal('nsfw') |
203 | }) | 203 | }) |
204 | 204 | ||
205 | it('Should display NSFW videos when the nsfw param === true', async function () { | 205 | it('Should display NSFW videos when the nsfw param === true', async function () { |
@@ -208,7 +208,7 @@ describe('Test video NSFW policy', function () { | |||
208 | 208 | ||
209 | const videos = res.body.data | 209 | const videos = res.body.data |
210 | expect(videos).to.have.lengthOf(1) | 210 | expect(videos).to.have.lengthOf(1) |
211 | expect(videos[ 0 ].name).to.equal('nsfw') | 211 | expect(videos[0].name).to.equal('nsfw') |
212 | } | 212 | } |
213 | }) | 213 | }) |
214 | 214 | ||
@@ -218,7 +218,7 @@ describe('Test video NSFW policy', function () { | |||
218 | 218 | ||
219 | const videos = res.body.data | 219 | const videos = res.body.data |
220 | expect(videos).to.have.lengthOf(1) | 220 | expect(videos).to.have.lengthOf(1) |
221 | expect(videos[ 0 ].name).to.equal('normal') | 221 | expect(videos[0].name).to.equal('normal') |
222 | } | 222 | } |
223 | }) | 223 | }) |
224 | 224 | ||
@@ -228,8 +228,8 @@ describe('Test video NSFW policy', function () { | |||
228 | 228 | ||
229 | const videos = res.body.data | 229 | const videos = res.body.data |
230 | expect(videos).to.have.lengthOf(2) | 230 | expect(videos).to.have.lengthOf(2) |
231 | expect(videos[ 0 ].name).to.equal('normal') | 231 | expect(videos[0].name).to.equal('normal') |
232 | expect(videos[ 1 ].name).to.equal('nsfw') | 232 | expect(videos[1].name).to.equal('nsfw') |
233 | } | 233 | } |
234 | }) | 234 | }) |
235 | }) | 235 | }) |
diff --git a/server/tests/api/videos/video-playlist-thumbnails.ts b/server/tests/api/videos/video-playlist-thumbnails.ts index 73ab02c17..a93a0b7de 100644 --- a/server/tests/api/videos/video-playlist-thumbnails.ts +++ b/server/tests/api/videos/video-playlist-thumbnails.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -8,14 +8,15 @@ import { | |||
8 | createVideoPlaylist, | 8 | createVideoPlaylist, |
9 | doubleFollow, | 9 | doubleFollow, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
11 | getVideoPlaylistsList, removeVideoFromPlaylist, | 11 | getVideoPlaylistsList, |
12 | removeVideoFromPlaylist, | ||
13 | reorderVideosPlaylist, | ||
12 | ServerInfo, | 14 | ServerInfo, |
13 | setAccessTokensToServers, | 15 | setAccessTokensToServers, |
14 | setDefaultVideoChannel, | 16 | setDefaultVideoChannel, |
15 | testImage, | 17 | testImage, |
16 | uploadVideoAndGetId, | 18 | uploadVideoAndGetId, |
17 | waitJobs, | 19 | waitJobs |
18 | reorderVideosPlaylist | ||
19 | } from '../../../../shared/extra-utils' | 20 | } from '../../../../shared/extra-utils' |
20 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' | 21 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' |
21 | 22 | ||
@@ -69,19 +70,19 @@ describe('Playlist thumbnail', function () { | |||
69 | this.timeout(30000) | 70 | this.timeout(30000) |
70 | 71 | ||
71 | const res = await createVideoPlaylist({ | 72 | const res = await createVideoPlaylist({ |
72 | url: servers[ 1 ].url, | 73 | url: servers[1].url, |
73 | token: servers[ 1 ].accessToken, | 74 | token: servers[1].accessToken, |
74 | playlistAttrs: { | 75 | playlistAttrs: { |
75 | displayName: 'playlist without thumbnail', | 76 | displayName: 'playlist without thumbnail', |
76 | privacy: VideoPlaylistPrivacy.PUBLIC, | 77 | privacy: VideoPlaylistPrivacy.PUBLIC, |
77 | videoChannelId: servers[ 1 ].videoChannel.id | 78 | videoChannelId: servers[1].videoChannel.id |
78 | } | 79 | } |
79 | }) | 80 | }) |
80 | playlistWithoutThumbnail = res.body.videoPlaylist.id | 81 | playlistWithoutThumbnail = res.body.videoPlaylist.id |
81 | 82 | ||
82 | const res2 = await addVideoInPlaylist({ | 83 | const res2 = await addVideoInPlaylist({ |
83 | url: servers[ 1 ].url, | 84 | url: servers[1].url, |
84 | token: servers[ 1 ].accessToken, | 85 | token: servers[1].accessToken, |
85 | playlistId: playlistWithoutThumbnail, | 86 | playlistId: playlistWithoutThumbnail, |
86 | elementAttrs: { videoId: video1 } | 87 | elementAttrs: { videoId: video1 } |
87 | }) | 88 | }) |
@@ -99,20 +100,20 @@ describe('Playlist thumbnail', function () { | |||
99 | this.timeout(30000) | 100 | this.timeout(30000) |
100 | 101 | ||
101 | const res = await createVideoPlaylist({ | 102 | const res = await createVideoPlaylist({ |
102 | url: servers[ 1 ].url, | 103 | url: servers[1].url, |
103 | token: servers[ 1 ].accessToken, | 104 | token: servers[1].accessToken, |
104 | playlistAttrs: { | 105 | playlistAttrs: { |
105 | displayName: 'playlist with thumbnail', | 106 | displayName: 'playlist with thumbnail', |
106 | privacy: VideoPlaylistPrivacy.PUBLIC, | 107 | privacy: VideoPlaylistPrivacy.PUBLIC, |
107 | videoChannelId: servers[ 1 ].videoChannel.id, | 108 | videoChannelId: servers[1].videoChannel.id, |
108 | thumbnailfile: 'thumbnail.jpg' | 109 | thumbnailfile: 'thumbnail.jpg' |
109 | } | 110 | } |
110 | }) | 111 | }) |
111 | playlistWithThumbnail = res.body.videoPlaylist.id | 112 | playlistWithThumbnail = res.body.videoPlaylist.id |
112 | 113 | ||
113 | const res2 = await addVideoInPlaylist({ | 114 | const res2 = await addVideoInPlaylist({ |
114 | url: servers[ 1 ].url, | 115 | url: servers[1].url, |
115 | token: servers[ 1 ].accessToken, | 116 | token: servers[1].accessToken, |
116 | playlistId: playlistWithThumbnail, | 117 | playlistId: playlistWithThumbnail, |
117 | elementAttrs: { videoId: video1 } | 118 | elementAttrs: { videoId: video1 } |
118 | }) | 119 | }) |
@@ -130,8 +131,8 @@ describe('Playlist thumbnail', function () { | |||
130 | this.timeout(30000) | 131 | this.timeout(30000) |
131 | 132 | ||
132 | const res = await addVideoInPlaylist({ | 133 | const res = await addVideoInPlaylist({ |
133 | url: servers[ 1 ].url, | 134 | url: servers[1].url, |
134 | token: servers[ 1 ].accessToken, | 135 | token: servers[1].accessToken, |
135 | playlistId: playlistWithoutThumbnail, | 136 | playlistId: playlistWithoutThumbnail, |
136 | elementAttrs: { videoId: video2 } | 137 | elementAttrs: { videoId: video2 } |
137 | }) | 138 | }) |
@@ -159,8 +160,8 @@ describe('Playlist thumbnail', function () { | |||
159 | this.timeout(30000) | 160 | this.timeout(30000) |
160 | 161 | ||
161 | const res = await addVideoInPlaylist({ | 162 | const res = await addVideoInPlaylist({ |
162 | url: servers[ 1 ].url, | 163 | url: servers[1].url, |
163 | token: servers[ 1 ].accessToken, | 164 | token: servers[1].accessToken, |
164 | playlistId: playlistWithThumbnail, | 165 | playlistId: playlistWithThumbnail, |
165 | elementAttrs: { videoId: video2 } | 166 | elementAttrs: { videoId: video2 } |
166 | }) | 167 | }) |
@@ -188,8 +189,8 @@ describe('Playlist thumbnail', function () { | |||
188 | this.timeout(30000) | 189 | this.timeout(30000) |
189 | 190 | ||
190 | await removeVideoFromPlaylist({ | 191 | await removeVideoFromPlaylist({ |
191 | url: servers[ 1 ].url, | 192 | url: servers[1].url, |
192 | token: servers[ 1 ].accessToken, | 193 | token: servers[1].accessToken, |
193 | playlistId: playlistWithoutThumbnail, | 194 | playlistId: playlistWithoutThumbnail, |
194 | playlistElementId: withoutThumbnailE1 | 195 | playlistElementId: withoutThumbnailE1 |
195 | }) | 196 | }) |
@@ -206,8 +207,8 @@ describe('Playlist thumbnail', function () { | |||
206 | this.timeout(30000) | 207 | this.timeout(30000) |
207 | 208 | ||
208 | await removeVideoFromPlaylist({ | 209 | await removeVideoFromPlaylist({ |
209 | url: servers[ 1 ].url, | 210 | url: servers[1].url, |
210 | token: servers[ 1 ].accessToken, | 211 | token: servers[1].accessToken, |
211 | playlistId: playlistWithThumbnail, | 212 | playlistId: playlistWithThumbnail, |
212 | playlistElementId: withThumbnailE1 | 213 | playlistElementId: withThumbnailE1 |
213 | }) | 214 | }) |
@@ -224,8 +225,8 @@ describe('Playlist thumbnail', function () { | |||
224 | this.timeout(30000) | 225 | this.timeout(30000) |
225 | 226 | ||
226 | await removeVideoFromPlaylist({ | 227 | await removeVideoFromPlaylist({ |
227 | url: servers[ 1 ].url, | 228 | url: servers[1].url, |
228 | token: servers[ 1 ].accessToken, | 229 | token: servers[1].accessToken, |
229 | playlistId: playlistWithoutThumbnail, | 230 | playlistId: playlistWithoutThumbnail, |
230 | playlistElementId: withoutThumbnailE2 | 231 | playlistElementId: withoutThumbnailE2 |
231 | }) | 232 | }) |
@@ -242,8 +243,8 @@ describe('Playlist thumbnail', function () { | |||
242 | this.timeout(30000) | 243 | this.timeout(30000) |
243 | 244 | ||
244 | await removeVideoFromPlaylist({ | 245 | await removeVideoFromPlaylist({ |
245 | url: servers[ 1 ].url, | 246 | url: servers[1].url, |
246 | token: servers[ 1 ].accessToken, | 247 | token: servers[1].accessToken, |
247 | playlistId: playlistWithThumbnail, | 248 | playlistId: playlistWithThumbnail, |
248 | playlistElementId: withThumbnailE2 | 249 | playlistElementId: withThumbnailE2 |
249 | }) | 250 | }) |
diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts index 9fd48ac7c..2bb97d7a8 100644 --- a/server/tests/api/videos/video-playlists.ts +++ b/server/tests/api/videos/video-playlists.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -141,12 +141,12 @@ describe('Test video playlists', function () { | |||
141 | servers[2].videos = await Promise.all(serverPromises[2]) | 141 | servers[2].videos = await Promise.all(serverPromises[2]) |
142 | } | 142 | } |
143 | 143 | ||
144 | nsfwVideoServer1 = (await uploadVideoAndGetId({ server: servers[ 0 ], videoName: 'NSFW video', nsfw: true })).id | 144 | nsfwVideoServer1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'NSFW video', nsfw: true })).id |
145 | 145 | ||
146 | { | 146 | { |
147 | await createUser({ | 147 | await createUser({ |
148 | url: servers[ 0 ].url, | 148 | url: servers[0].url, |
149 | accessToken: servers[ 0 ].accessToken, | 149 | accessToken: servers[0].accessToken, |
150 | username: 'user1', | 150 | username: 'user1', |
151 | password: 'password' | 151 | password: 'password' |
152 | }) | 152 | }) |
@@ -158,17 +158,17 @@ describe('Test video playlists', function () { | |||
158 | 158 | ||
159 | describe('Get default playlists', function () { | 159 | describe('Get default playlists', function () { |
160 | it('Should list video playlist privacies', async function () { | 160 | it('Should list video playlist privacies', async function () { |
161 | const res = await getVideoPlaylistPrivacies(servers[ 0 ].url) | 161 | const res = await getVideoPlaylistPrivacies(servers[0].url) |
162 | 162 | ||
163 | const privacies = res.body | 163 | const privacies = res.body |
164 | expect(Object.keys(privacies)).to.have.length.at.least(3) | 164 | expect(Object.keys(privacies)).to.have.length.at.least(3) |
165 | 165 | ||
166 | expect(privacies[ 3 ]).to.equal('Private') | 166 | expect(privacies[3]).to.equal('Private') |
167 | }) | 167 | }) |
168 | 168 | ||
169 | it('Should list watch later playlist', async function () { | 169 | it('Should list watch later playlist', async function () { |
170 | const url = servers[ 0 ].url | 170 | const url = servers[0].url |
171 | const accessToken = servers[ 0 ].accessToken | 171 | const accessToken = servers[0].accessToken |
172 | 172 | ||
173 | { | 173 | { |
174 | const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.WATCH_LATER) | 174 | const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.WATCH_LATER) |
@@ -176,7 +176,7 @@ describe('Test video playlists', function () { | |||
176 | expect(res.body.total).to.equal(1) | 176 | expect(res.body.total).to.equal(1) |
177 | expect(res.body.data).to.have.lengthOf(1) | 177 | expect(res.body.data).to.have.lengthOf(1) |
178 | 178 | ||
179 | const playlist: VideoPlaylist = res.body.data[ 0 ] | 179 | const playlist: VideoPlaylist = res.body.data[0] |
180 | expect(playlist.displayName).to.equal('Watch later') | 180 | expect(playlist.displayName).to.equal('Watch later') |
181 | expect(playlist.type.id).to.equal(VideoPlaylistType.WATCH_LATER) | 181 | expect(playlist.type.id).to.equal(VideoPlaylistType.WATCH_LATER) |
182 | expect(playlist.type.label).to.equal('Watch later') | 182 | expect(playlist.type.label).to.equal('Watch later') |
@@ -197,15 +197,15 @@ describe('Test video playlists', function () { | |||
197 | }) | 197 | }) |
198 | 198 | ||
199 | it('Should get private playlist for a classic user', async function () { | 199 | it('Should get private playlist for a classic user', async function () { |
200 | const token = await generateUserAccessToken(servers[ 0 ], 'toto') | 200 | const token = await generateUserAccessToken(servers[0], 'toto') |
201 | 201 | ||
202 | const res = await getAccountPlaylistsListWithToken(servers[ 0 ].url, token, 'toto', 0, 5) | 202 | const res = await getAccountPlaylistsListWithToken(servers[0].url, token, 'toto', 0, 5) |
203 | 203 | ||
204 | expect(res.body.total).to.equal(1) | 204 | expect(res.body.total).to.equal(1) |
205 | expect(res.body.data).to.have.lengthOf(1) | 205 | expect(res.body.data).to.have.lengthOf(1) |
206 | 206 | ||
207 | const playlistId = res.body.data[ 0 ].id | 207 | const playlistId = res.body.data[0].id |
208 | await getPlaylistVideos(servers[ 0 ].url, token, playlistId, 0, 5) | 208 | await getPlaylistVideos(servers[0].url, token, playlistId, 0, 5) |
209 | }) | 209 | }) |
210 | }) | 210 | }) |
211 | 211 | ||
@@ -215,14 +215,14 @@ describe('Test video playlists', function () { | |||
215 | this.timeout(30000) | 215 | this.timeout(30000) |
216 | 216 | ||
217 | await createVideoPlaylist({ | 217 | await createVideoPlaylist({ |
218 | url: servers[ 0 ].url, | 218 | url: servers[0].url, |
219 | token: servers[ 0 ].accessToken, | 219 | token: servers[0].accessToken, |
220 | playlistAttrs: { | 220 | playlistAttrs: { |
221 | displayName: 'my super playlist', | 221 | displayName: 'my super playlist', |
222 | privacy: VideoPlaylistPrivacy.PUBLIC, | 222 | privacy: VideoPlaylistPrivacy.PUBLIC, |
223 | description: 'my super description', | 223 | description: 'my super description', |
224 | thumbnailfile: 'thumbnail.jpg', | 224 | thumbnailfile: 'thumbnail.jpg', |
225 | videoChannelId: servers[ 0 ].videoChannel.id | 225 | videoChannelId: servers[0].videoChannel.id |
226 | } | 226 | } |
227 | }) | 227 | }) |
228 | 228 | ||
@@ -233,7 +233,7 @@ describe('Test video playlists', function () { | |||
233 | expect(res.body.total).to.equal(1) | 233 | expect(res.body.total).to.equal(1) |
234 | expect(res.body.data).to.have.lengthOf(1) | 234 | expect(res.body.data).to.have.lengthOf(1) |
235 | 235 | ||
236 | const playlistFromList = res.body.data[ 0 ] as VideoPlaylist | 236 | const playlistFromList = res.body.data[0] as VideoPlaylist |
237 | 237 | ||
238 | const res2 = await getVideoPlaylist(server.url, playlistFromList.uuid) | 238 | const res2 = await getVideoPlaylist(server.url, playlistFromList.uuid) |
239 | const playlistFromGet = res2.body | 239 | const playlistFromGet = res2.body |
@@ -266,12 +266,12 @@ describe('Test video playlists', function () { | |||
266 | 266 | ||
267 | { | 267 | { |
268 | const res = await createVideoPlaylist({ | 268 | const res = await createVideoPlaylist({ |
269 | url: servers[ 1 ].url, | 269 | url: servers[1].url, |
270 | token: servers[ 1 ].accessToken, | 270 | token: servers[1].accessToken, |
271 | playlistAttrs: { | 271 | playlistAttrs: { |
272 | displayName: 'playlist 2', | 272 | displayName: 'playlist 2', |
273 | privacy: VideoPlaylistPrivacy.PUBLIC, | 273 | privacy: VideoPlaylistPrivacy.PUBLIC, |
274 | videoChannelId: servers[ 1 ].videoChannel.id | 274 | videoChannelId: servers[1].videoChannel.id |
275 | } | 275 | } |
276 | }) | 276 | }) |
277 | playlistServer2Id1 = res.body.videoPlaylist.id | 277 | playlistServer2Id1 = res.body.videoPlaylist.id |
@@ -279,13 +279,13 @@ describe('Test video playlists', function () { | |||
279 | 279 | ||
280 | { | 280 | { |
281 | const res = await createVideoPlaylist({ | 281 | const res = await createVideoPlaylist({ |
282 | url: servers[ 1 ].url, | 282 | url: servers[1].url, |
283 | token: servers[ 1 ].accessToken, | 283 | token: servers[1].accessToken, |
284 | playlistAttrs: { | 284 | playlistAttrs: { |
285 | displayName: 'playlist 3', | 285 | displayName: 'playlist 3', |
286 | privacy: VideoPlaylistPrivacy.PUBLIC, | 286 | privacy: VideoPlaylistPrivacy.PUBLIC, |
287 | thumbnailfile: 'thumbnail.jpg', | 287 | thumbnailfile: 'thumbnail.jpg', |
288 | videoChannelId: servers[ 1 ].videoChannel.id | 288 | videoChannelId: servers[1].videoChannel.id |
289 | } | 289 | } |
290 | }) | 290 | }) |
291 | 291 | ||
@@ -293,24 +293,24 @@ describe('Test video playlists', function () { | |||
293 | playlistServer2UUID2 = res.body.videoPlaylist.uuid | 293 | playlistServer2UUID2 = res.body.videoPlaylist.uuid |
294 | } | 294 | } |
295 | 295 | ||
296 | for (let id of [ playlistServer2Id1, playlistServer2Id2 ]) { | 296 | for (const id of [ playlistServer2Id1, playlistServer2Id2 ]) { |
297 | await addVideoInPlaylist({ | 297 | await addVideoInPlaylist({ |
298 | url: servers[ 1 ].url, | 298 | url: servers[1].url, |
299 | token: servers[ 1 ].accessToken, | 299 | token: servers[1].accessToken, |
300 | playlistId: id, | 300 | playlistId: id, |
301 | elementAttrs: { videoId: servers[ 1 ].videos[ 0 ].id, startTimestamp: 1, stopTimestamp: 2 } | 301 | elementAttrs: { videoId: servers[1].videos[0].id, startTimestamp: 1, stopTimestamp: 2 } |
302 | }) | 302 | }) |
303 | await addVideoInPlaylist({ | 303 | await addVideoInPlaylist({ |
304 | url: servers[ 1 ].url, | 304 | url: servers[1].url, |
305 | token: servers[ 1 ].accessToken, | 305 | token: servers[1].accessToken, |
306 | playlistId: id, | 306 | playlistId: id, |
307 | elementAttrs: { videoId: servers[ 1 ].videos[ 1 ].id } | 307 | elementAttrs: { videoId: servers[1].videos[1].id } |
308 | }) | 308 | }) |
309 | } | 309 | } |
310 | 310 | ||
311 | await waitJobs(servers) | 311 | await waitJobs(servers) |
312 | 312 | ||
313 | for (const server of [ servers[ 0 ], servers[ 1 ] ]) { | 313 | for (const server of [ servers[0], servers[1] ]) { |
314 | const res = await getVideoPlaylistsList(server.url, 0, 5) | 314 | const res = await getVideoPlaylistsList(server.url, 0, 5) |
315 | 315 | ||
316 | const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2') | 316 | const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2') |
@@ -322,7 +322,7 @@ describe('Test video playlists', function () { | |||
322 | await testImage(server.url, 'thumbnail', playlist3.thumbnailPath) | 322 | await testImage(server.url, 'thumbnail', playlist3.thumbnailPath) |
323 | } | 323 | } |
324 | 324 | ||
325 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) | 325 | const res = await getVideoPlaylistsList(servers[2].url, 0, 5) |
326 | expect(res.body.data.find(p => p.displayName === 'playlist 2')).to.be.undefined | 326 | expect(res.body.data.find(p => p.displayName === 'playlist 2')).to.be.undefined |
327 | expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.be.undefined | 327 | expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.be.undefined |
328 | }) | 328 | }) |
@@ -331,13 +331,13 @@ describe('Test video playlists', function () { | |||
331 | this.timeout(30000) | 331 | this.timeout(30000) |
332 | 332 | ||
333 | // Server 2 and server 3 follow each other | 333 | // Server 2 and server 3 follow each other |
334 | await doubleFollow(servers[ 1 ], servers[ 2 ]) | 334 | await doubleFollow(servers[1], servers[2]) |
335 | 335 | ||
336 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) | 336 | const res = await getVideoPlaylistsList(servers[2].url, 0, 5) |
337 | 337 | ||
338 | const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2') | 338 | const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2') |
339 | expect(playlist2).to.not.be.undefined | 339 | expect(playlist2).to.not.be.undefined |
340 | await testImage(servers[ 2 ].url, 'thumbnail-playlist', playlist2.thumbnailPath) | 340 | await testImage(servers[2].url, 'thumbnail-playlist', playlist2.thumbnailPath) |
341 | 341 | ||
342 | expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined | 342 | expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined |
343 | }) | 343 | }) |
@@ -349,25 +349,25 @@ describe('Test video playlists', function () { | |||
349 | this.timeout(30000) | 349 | this.timeout(30000) |
350 | 350 | ||
351 | { | 351 | { |
352 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, 'createdAt') | 352 | const res = await getVideoPlaylistsList(servers[2].url, 1, 2, 'createdAt') |
353 | 353 | ||
354 | expect(res.body.total).to.equal(3) | 354 | expect(res.body.total).to.equal(3) |
355 | 355 | ||
356 | const data: VideoPlaylist[] = res.body.data | 356 | const data: VideoPlaylist[] = res.body.data |
357 | expect(data).to.have.lengthOf(2) | 357 | expect(data).to.have.lengthOf(2) |
358 | expect(data[ 0 ].displayName).to.equal('playlist 2') | 358 | expect(data[0].displayName).to.equal('playlist 2') |
359 | expect(data[ 1 ].displayName).to.equal('playlist 3') | 359 | expect(data[1].displayName).to.equal('playlist 3') |
360 | } | 360 | } |
361 | 361 | ||
362 | { | 362 | { |
363 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, '-createdAt') | 363 | const res = await getVideoPlaylistsList(servers[2].url, 1, 2, '-createdAt') |
364 | 364 | ||
365 | expect(res.body.total).to.equal(3) | 365 | expect(res.body.total).to.equal(3) |
366 | 366 | ||
367 | const data: VideoPlaylist[] = res.body.data | 367 | const data: VideoPlaylist[] = res.body.data |
368 | expect(data).to.have.lengthOf(2) | 368 | expect(data).to.have.lengthOf(2) |
369 | expect(data[ 0 ].displayName).to.equal('playlist 2') | 369 | expect(data[0].displayName).to.equal('playlist 2') |
370 | expect(data[ 1 ].displayName).to.equal('my super playlist') | 370 | expect(data[1].displayName).to.equal('my super playlist') |
371 | } | 371 | } |
372 | }) | 372 | }) |
373 | 373 | ||
@@ -375,13 +375,13 @@ describe('Test video playlists', function () { | |||
375 | this.timeout(30000) | 375 | this.timeout(30000) |
376 | 376 | ||
377 | { | 377 | { |
378 | const res = await getVideoChannelPlaylistsList(servers[ 0 ].url, 'root_channel', 0, 2, '-createdAt') | 378 | const res = await getVideoChannelPlaylistsList(servers[0].url, 'root_channel', 0, 2, '-createdAt') |
379 | 379 | ||
380 | expect(res.body.total).to.equal(1) | 380 | expect(res.body.total).to.equal(1) |
381 | 381 | ||
382 | const data: VideoPlaylist[] = res.body.data | 382 | const data: VideoPlaylist[] = res.body.data |
383 | expect(data).to.have.lengthOf(1) | 383 | expect(data).to.have.lengthOf(1) |
384 | expect(data[ 0 ].displayName).to.equal('my super playlist') | 384 | expect(data[0].displayName).to.equal('my super playlist') |
385 | } | 385 | } |
386 | }) | 386 | }) |
387 | 387 | ||
@@ -389,37 +389,37 @@ describe('Test video playlists', function () { | |||
389 | this.timeout(30000) | 389 | this.timeout(30000) |
390 | 390 | ||
391 | { | 391 | { |
392 | const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, '-createdAt') | 392 | const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, '-createdAt') |
393 | 393 | ||
394 | expect(res.body.total).to.equal(2) | 394 | expect(res.body.total).to.equal(2) |
395 | 395 | ||
396 | const data: VideoPlaylist[] = res.body.data | 396 | const data: VideoPlaylist[] = res.body.data |
397 | expect(data).to.have.lengthOf(1) | 397 | expect(data).to.have.lengthOf(1) |
398 | expect(data[ 0 ].displayName).to.equal('playlist 2') | 398 | expect(data[0].displayName).to.equal('playlist 2') |
399 | } | 399 | } |
400 | 400 | ||
401 | { | 401 | { |
402 | const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, 'createdAt') | 402 | const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, 'createdAt') |
403 | 403 | ||
404 | expect(res.body.total).to.equal(2) | 404 | expect(res.body.total).to.equal(2) |
405 | 405 | ||
406 | const data: VideoPlaylist[] = res.body.data | 406 | const data: VideoPlaylist[] = res.body.data |
407 | expect(data).to.have.lengthOf(1) | 407 | expect(data).to.have.lengthOf(1) |
408 | expect(data[ 0 ].displayName).to.equal('playlist 3') | 408 | expect(data[0].displayName).to.equal('playlist 3') |
409 | } | 409 | } |
410 | 410 | ||
411 | { | 411 | { |
412 | const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 0, 10, 'createdAt', '3') | 412 | const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '3') |
413 | 413 | ||
414 | expect(res.body.total).to.equal(1) | 414 | expect(res.body.total).to.equal(1) |
415 | 415 | ||
416 | const data: VideoPlaylist[] = res.body.data | 416 | const data: VideoPlaylist[] = res.body.data |
417 | expect(data).to.have.lengthOf(1) | 417 | expect(data).to.have.lengthOf(1) |
418 | expect(data[ 0 ].displayName).to.equal('playlist 3') | 418 | expect(data[0].displayName).to.equal('playlist 3') |
419 | } | 419 | } |
420 | 420 | ||
421 | { | 421 | { |
422 | const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 0, 10, 'createdAt', '4') | 422 | const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '4') |
423 | 423 | ||
424 | expect(res.body.total).to.equal(0) | 424 | expect(res.body.total).to.equal(0) |
425 | 425 | ||
@@ -432,8 +432,8 @@ describe('Test video playlists', function () { | |||
432 | this.timeout(30000) | 432 | this.timeout(30000) |
433 | 433 | ||
434 | await createVideoPlaylist({ | 434 | await createVideoPlaylist({ |
435 | url: servers[ 1 ].url, | 435 | url: servers[1].url, |
436 | token: servers[ 1 ].accessToken, | 436 | token: servers[1].accessToken, |
437 | playlistAttrs: { | 437 | playlistAttrs: { |
438 | displayName: 'playlist unlisted', | 438 | displayName: 'playlist unlisted', |
439 | privacy: VideoPlaylistPrivacy.UNLISTED | 439 | privacy: VideoPlaylistPrivacy.UNLISTED |
@@ -441,8 +441,8 @@ describe('Test video playlists', function () { | |||
441 | }) | 441 | }) |
442 | 442 | ||
443 | await createVideoPlaylist({ | 443 | await createVideoPlaylist({ |
444 | url: servers[ 1 ].url, | 444 | url: servers[1].url, |
445 | token: servers[ 1 ].accessToken, | 445 | token: servers[1].accessToken, |
446 | playlistAttrs: { | 446 | playlistAttrs: { |
447 | displayName: 'playlist private', | 447 | displayName: 'playlist private', |
448 | privacy: VideoPlaylistPrivacy.PRIVATE | 448 | privacy: VideoPlaylistPrivacy.PRIVATE |
@@ -453,18 +453,18 @@ describe('Test video playlists', function () { | |||
453 | 453 | ||
454 | for (const server of servers) { | 454 | for (const server of servers) { |
455 | const results = [ | 455 | const results = [ |
456 | await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[ 1 ].port, 0, 5, '-createdAt'), | 456 | await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'), |
457 | await getVideoPlaylistsList(server.url, 0, 2, '-createdAt') | 457 | await getVideoPlaylistsList(server.url, 0, 2, '-createdAt') |
458 | ] | 458 | ] |
459 | 459 | ||
460 | expect(results[ 0 ].body.total).to.equal(2) | 460 | expect(results[0].body.total).to.equal(2) |
461 | expect(results[ 1 ].body.total).to.equal(3) | 461 | expect(results[1].body.total).to.equal(3) |
462 | 462 | ||
463 | for (const res of results) { | 463 | for (const res of results) { |
464 | const data: VideoPlaylist[] = res.body.data | 464 | const data: VideoPlaylist[] = res.body.data |
465 | expect(data).to.have.lengthOf(2) | 465 | expect(data).to.have.lengthOf(2) |
466 | expect(data[ 0 ].displayName).to.equal('playlist 3') | 466 | expect(data[0].displayName).to.equal('playlist 3') |
467 | expect(data[ 1 ].displayName).to.equal('playlist 2') | 467 | expect(data[1].displayName).to.equal('playlist 2') |
468 | } | 468 | } |
469 | } | 469 | } |
470 | }) | 470 | }) |
@@ -519,32 +519,32 @@ describe('Test video playlists', function () { | |||
519 | this.timeout(30000) | 519 | this.timeout(30000) |
520 | 520 | ||
521 | const addVideo = (elementAttrs: any) => { | 521 | const addVideo = (elementAttrs: any) => { |
522 | return addVideoInPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: playlistServer1Id, elementAttrs }) | 522 | return addVideoInPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: playlistServer1Id, elementAttrs }) |
523 | } | 523 | } |
524 | 524 | ||
525 | const res = await createVideoPlaylist({ | 525 | const res = await createVideoPlaylist({ |
526 | url: servers[ 0 ].url, | 526 | url: servers[0].url, |
527 | token: servers[ 0 ].accessToken, | 527 | token: servers[0].accessToken, |
528 | playlistAttrs: { | 528 | playlistAttrs: { |
529 | displayName: 'playlist 4', | 529 | displayName: 'playlist 4', |
530 | privacy: VideoPlaylistPrivacy.PUBLIC, | 530 | privacy: VideoPlaylistPrivacy.PUBLIC, |
531 | videoChannelId: servers[ 0 ].videoChannel.id | 531 | videoChannelId: servers[0].videoChannel.id |
532 | } | 532 | } |
533 | }) | 533 | }) |
534 | 534 | ||
535 | playlistServer1Id = res.body.videoPlaylist.id | 535 | playlistServer1Id = res.body.videoPlaylist.id |
536 | playlistServer1UUID = res.body.videoPlaylist.uuid | 536 | playlistServer1UUID = res.body.videoPlaylist.uuid |
537 | 537 | ||
538 | await addVideo({ videoId: servers[ 0 ].videos[ 0 ].uuid, startTimestamp: 15, stopTimestamp: 28 }) | 538 | await addVideo({ videoId: servers[0].videos[0].uuid, startTimestamp: 15, stopTimestamp: 28 }) |
539 | await addVideo({ videoId: servers[ 2 ].videos[ 1 ].uuid, startTimestamp: 35 }) | 539 | await addVideo({ videoId: servers[2].videos[1].uuid, startTimestamp: 35 }) |
540 | await addVideo({ videoId: servers[ 2 ].videos[ 2 ].uuid }) | 540 | await addVideo({ videoId: servers[2].videos[2].uuid }) |
541 | { | 541 | { |
542 | const res = await addVideo({ videoId: servers[ 0 ].videos[ 3 ].uuid, stopTimestamp: 35 }) | 542 | const res = await addVideo({ videoId: servers[0].videos[3].uuid, stopTimestamp: 35 }) |
543 | playlistElementServer1Video4 = res.body.videoPlaylistElement.id | 543 | playlistElementServer1Video4 = res.body.videoPlaylistElement.id |
544 | } | 544 | } |
545 | 545 | ||
546 | { | 546 | { |
547 | const res = await addVideo({ videoId: servers[ 0 ].videos[ 4 ].uuid, startTimestamp: 45, stopTimestamp: 60 }) | 547 | const res = await addVideo({ videoId: servers[0].videos[4].uuid, startTimestamp: 45, stopTimestamp: 60 }) |
548 | playlistElementServer1Video5 = res.body.videoPlaylistElement.id | 548 | playlistElementServer1Video5 = res.body.videoPlaylistElement.id |
549 | } | 549 | } |
550 | 550 | ||
@@ -567,35 +567,35 @@ describe('Test video playlists', function () { | |||
567 | const videoElements: VideoPlaylistElement[] = res.body.data | 567 | const videoElements: VideoPlaylistElement[] = res.body.data |
568 | expect(videoElements).to.have.lengthOf(6) | 568 | expect(videoElements).to.have.lengthOf(6) |
569 | 569 | ||
570 | expect(videoElements[ 0 ].video.name).to.equal('video 0 server 1') | 570 | expect(videoElements[0].video.name).to.equal('video 0 server 1') |
571 | expect(videoElements[ 0 ].position).to.equal(1) | 571 | expect(videoElements[0].position).to.equal(1) |
572 | expect(videoElements[ 0 ].startTimestamp).to.equal(15) | 572 | expect(videoElements[0].startTimestamp).to.equal(15) |
573 | expect(videoElements[ 0 ].stopTimestamp).to.equal(28) | 573 | expect(videoElements[0].stopTimestamp).to.equal(28) |
574 | 574 | ||
575 | expect(videoElements[ 1 ].video.name).to.equal('video 1 server 3') | 575 | expect(videoElements[1].video.name).to.equal('video 1 server 3') |
576 | expect(videoElements[ 1 ].position).to.equal(2) | 576 | expect(videoElements[1].position).to.equal(2) |
577 | expect(videoElements[ 1 ].startTimestamp).to.equal(35) | 577 | expect(videoElements[1].startTimestamp).to.equal(35) |
578 | expect(videoElements[ 1 ].stopTimestamp).to.be.null | 578 | expect(videoElements[1].stopTimestamp).to.be.null |
579 | 579 | ||
580 | expect(videoElements[ 2 ].video.name).to.equal('video 2 server 3') | 580 | expect(videoElements[2].video.name).to.equal('video 2 server 3') |
581 | expect(videoElements[ 2 ].position).to.equal(3) | 581 | expect(videoElements[2].position).to.equal(3) |
582 | expect(videoElements[ 2 ].startTimestamp).to.be.null | 582 | expect(videoElements[2].startTimestamp).to.be.null |
583 | expect(videoElements[ 2 ].stopTimestamp).to.be.null | 583 | expect(videoElements[2].stopTimestamp).to.be.null |
584 | 584 | ||
585 | expect(videoElements[ 3 ].video.name).to.equal('video 3 server 1') | 585 | expect(videoElements[3].video.name).to.equal('video 3 server 1') |
586 | expect(videoElements[ 3 ].position).to.equal(4) | 586 | expect(videoElements[3].position).to.equal(4) |
587 | expect(videoElements[ 3 ].startTimestamp).to.be.null | 587 | expect(videoElements[3].startTimestamp).to.be.null |
588 | expect(videoElements[ 3 ].stopTimestamp).to.equal(35) | 588 | expect(videoElements[3].stopTimestamp).to.equal(35) |
589 | 589 | ||
590 | expect(videoElements[ 4 ].video.name).to.equal('video 4 server 1') | 590 | expect(videoElements[4].video.name).to.equal('video 4 server 1') |
591 | expect(videoElements[ 4 ].position).to.equal(5) | 591 | expect(videoElements[4].position).to.equal(5) |
592 | expect(videoElements[ 4 ].startTimestamp).to.equal(45) | 592 | expect(videoElements[4].startTimestamp).to.equal(45) |
593 | expect(videoElements[ 4 ].stopTimestamp).to.equal(60) | 593 | expect(videoElements[4].stopTimestamp).to.equal(60) |
594 | 594 | ||
595 | expect(videoElements[ 5 ].video.name).to.equal('NSFW video') | 595 | expect(videoElements[5].video.name).to.equal('NSFW video') |
596 | expect(videoElements[ 5 ].position).to.equal(6) | 596 | expect(videoElements[5].position).to.equal(6) |
597 | expect(videoElements[ 5 ].startTimestamp).to.equal(5) | 597 | expect(videoElements[5].startTimestamp).to.equal(5) |
598 | expect(videoElements[ 5 ].stopTimestamp).to.be.null | 598 | expect(videoElements[5].stopTimestamp).to.be.null |
599 | 599 | ||
600 | const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2) | 600 | const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2) |
601 | expect(res3.body.data).to.have.lengthOf(2) | 601 | expect(res3.body.data).to.have.lengthOf(2) |
@@ -616,18 +616,18 @@ describe('Test video playlists', function () { | |||
616 | before(async function () { | 616 | before(async function () { |
617 | this.timeout(30000) | 617 | this.timeout(30000) |
618 | 618 | ||
619 | groupUser1 = [ Object.assign({}, servers[ 0 ], { accessToken: userAccessTokenServer1 }) ] | 619 | groupUser1 = [ Object.assign({}, servers[0], { accessToken: userAccessTokenServer1 }) ] |
620 | groupWithoutToken1 = [ Object.assign({}, servers[ 0 ], { accessToken: undefined }) ] | 620 | groupWithoutToken1 = [ Object.assign({}, servers[0], { accessToken: undefined }) ] |
621 | group1 = [ servers[ 0 ] ] | 621 | group1 = [ servers[0] ] |
622 | group2 = [ servers[ 1 ], servers[ 2 ] ] | 622 | group2 = [ servers[1], servers[2] ] |
623 | 623 | ||
624 | const res = await createVideoPlaylist({ | 624 | const res = await createVideoPlaylist({ |
625 | url: servers[ 0 ].url, | 625 | url: servers[0].url, |
626 | token: userAccessTokenServer1, | 626 | token: userAccessTokenServer1, |
627 | playlistAttrs: { | 627 | playlistAttrs: { |
628 | displayName: 'playlist 56', | 628 | displayName: 'playlist 56', |
629 | privacy: VideoPlaylistPrivacy.PUBLIC, | 629 | privacy: VideoPlaylistPrivacy.PUBLIC, |
630 | videoChannelId: servers[ 0 ].videoChannel.id | 630 | videoChannelId: servers[0].videoChannel.id |
631 | } | 631 | } |
632 | }) | 632 | }) |
633 | 633 | ||
@@ -635,7 +635,7 @@ describe('Test video playlists', function () { | |||
635 | playlistServer1UUID2 = res.body.videoPlaylist.uuid | 635 | playlistServer1UUID2 = res.body.videoPlaylist.uuid |
636 | 636 | ||
637 | const addVideo = (elementAttrs: any) => { | 637 | const addVideo = (elementAttrs: any) => { |
638 | return addVideoInPlaylist({ url: servers[ 0 ].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs }) | 638 | return addVideoInPlaylist({ url: servers[0].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs }) |
639 | } | 639 | } |
640 | 640 | ||
641 | video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 89', token: userAccessTokenServer1 })).uuid | 641 | video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 89', token: userAccessTokenServer1 })).uuid |
@@ -656,7 +656,7 @@ describe('Test video playlists', function () { | |||
656 | const position = 1 | 656 | const position = 1 |
657 | 657 | ||
658 | { | 658 | { |
659 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PRIVATE }) | 659 | await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PRIVATE }) |
660 | await waitJobs(servers) | 660 | await waitJobs(servers) |
661 | 661 | ||
662 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 662 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
@@ -666,7 +666,7 @@ describe('Test video playlists', function () { | |||
666 | } | 666 | } |
667 | 667 | ||
668 | { | 668 | { |
669 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PUBLIC }) | 669 | await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PUBLIC }) |
670 | await waitJobs(servers) | 670 | await waitJobs(servers) |
671 | 671 | ||
672 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 672 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
@@ -684,7 +684,7 @@ describe('Test video playlists', function () { | |||
684 | const position = 1 | 684 | const position = 1 |
685 | 685 | ||
686 | { | 686 | { |
687 | await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1, 'reason', true) | 687 | await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video1, 'reason', true) |
688 | await waitJobs(servers) | 688 | await waitJobs(servers) |
689 | 689 | ||
690 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 690 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
@@ -694,7 +694,7 @@ describe('Test video playlists', function () { | |||
694 | } | 694 | } |
695 | 695 | ||
696 | { | 696 | { |
697 | await removeVideoFromBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1) | 697 | await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, video1) |
698 | await waitJobs(servers) | 698 | await waitJobs(servers) |
699 | 699 | ||
700 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 700 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
@@ -712,52 +712,52 @@ describe('Test video playlists', function () { | |||
712 | const position = 2 | 712 | const position = 2 |
713 | 713 | ||
714 | { | 714 | { |
715 | await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port) | 715 | await addAccountToAccountBlocklist(servers[0].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port) |
716 | await waitJobs(servers) | 716 | await waitJobs(servers) |
717 | 717 | ||
718 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) | 718 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) |
719 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 719 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
720 | 720 | ||
721 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port) | 721 | await removeAccountFromAccountBlocklist(servers[0].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port) |
722 | await waitJobs(servers) | 722 | await waitJobs(servers) |
723 | 723 | ||
724 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 724 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
725 | } | 725 | } |
726 | 726 | ||
727 | { | 727 | { |
728 | await addServerToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port) | 728 | await addServerToAccountBlocklist(servers[0].url, userAccessTokenServer1, 'localhost:' + servers[1].port) |
729 | await waitJobs(servers) | 729 | await waitJobs(servers) |
730 | 730 | ||
731 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) | 731 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) |
732 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 732 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
733 | 733 | ||
734 | await removeServerFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port) | 734 | await removeServerFromAccountBlocklist(servers[0].url, userAccessTokenServer1, 'localhost:' + servers[1].port) |
735 | await waitJobs(servers) | 735 | await waitJobs(servers) |
736 | 736 | ||
737 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 737 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
738 | } | 738 | } |
739 | 739 | ||
740 | { | 740 | { |
741 | await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port) | 741 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'root@localhost:' + servers[1].port) |
742 | await waitJobs(servers) | 742 | await waitJobs(servers) |
743 | 743 | ||
744 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) | 744 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) |
745 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 745 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
746 | 746 | ||
747 | await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port) | 747 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'root@localhost:' + servers[1].port) |
748 | await waitJobs(servers) | 748 | await waitJobs(servers) |
749 | 749 | ||
750 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 750 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
751 | } | 751 | } |
752 | 752 | ||
753 | { | 753 | { |
754 | await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 754 | await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
755 | await waitJobs(servers) | 755 | await waitJobs(servers) |
756 | 756 | ||
757 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) | 757 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) |
758 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 758 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
759 | 759 | ||
760 | await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 760 | await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
761 | await waitJobs(servers) | 761 | await waitJobs(servers) |
762 | 762 | ||
763 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 763 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
@@ -785,8 +785,8 @@ describe('Test video playlists', function () { | |||
785 | 785 | ||
786 | { | 786 | { |
787 | await reorderVideosPlaylist({ | 787 | await reorderVideosPlaylist({ |
788 | url: servers[ 0 ].url, | 788 | url: servers[0].url, |
789 | token: servers[ 0 ].accessToken, | 789 | token: servers[0].accessToken, |
790 | playlistId: playlistServer1Id, | 790 | playlistId: playlistServer1Id, |
791 | elementAttrs: { | 791 | elementAttrs: { |
792 | startPosition: 2, | 792 | startPosition: 2, |
@@ -813,8 +813,8 @@ describe('Test video playlists', function () { | |||
813 | 813 | ||
814 | { | 814 | { |
815 | await reorderVideosPlaylist({ | 815 | await reorderVideosPlaylist({ |
816 | url: servers[ 0 ].url, | 816 | url: servers[0].url, |
817 | token: servers[ 0 ].accessToken, | 817 | token: servers[0].accessToken, |
818 | playlistId: playlistServer1Id, | 818 | playlistId: playlistServer1Id, |
819 | elementAttrs: { | 819 | elementAttrs: { |
820 | startPosition: 1, | 820 | startPosition: 1, |
@@ -842,8 +842,8 @@ describe('Test video playlists', function () { | |||
842 | 842 | ||
843 | { | 843 | { |
844 | await reorderVideosPlaylist({ | 844 | await reorderVideosPlaylist({ |
845 | url: servers[ 0 ].url, | 845 | url: servers[0].url, |
846 | token: servers[ 0 ].accessToken, | 846 | token: servers[0].accessToken, |
847 | playlistId: playlistServer1Id, | 847 | playlistId: playlistServer1Id, |
848 | elementAttrs: { | 848 | elementAttrs: { |
849 | startPosition: 6, | 849 | startPosition: 6, |
@@ -868,7 +868,7 @@ describe('Test video playlists', function () { | |||
868 | ]) | 868 | ]) |
869 | 869 | ||
870 | for (let i = 1; i <= elements.length; i++) { | 870 | for (let i = 1; i <= elements.length; i++) { |
871 | expect(elements[ i - 1 ].position).to.equal(i) | 871 | expect(elements[i - 1].position).to.equal(i) |
872 | } | 872 | } |
873 | } | 873 | } |
874 | } | 874 | } |
@@ -878,8 +878,8 @@ describe('Test video playlists', function () { | |||
878 | this.timeout(30000) | 878 | this.timeout(30000) |
879 | 879 | ||
880 | await updateVideoPlaylistElement({ | 880 | await updateVideoPlaylistElement({ |
881 | url: servers[ 0 ].url, | 881 | url: servers[0].url, |
882 | token: servers[ 0 ].accessToken, | 882 | token: servers[0].accessToken, |
883 | playlistId: playlistServer1Id, | 883 | playlistId: playlistServer1Id, |
884 | playlistElementId: playlistElementServer1Video4, | 884 | playlistElementId: playlistElementServer1Video4, |
885 | elementAttrs: { | 885 | elementAttrs: { |
@@ -888,8 +888,8 @@ describe('Test video playlists', function () { | |||
888 | }) | 888 | }) |
889 | 889 | ||
890 | await updateVideoPlaylistElement({ | 890 | await updateVideoPlaylistElement({ |
891 | url: servers[ 0 ].url, | 891 | url: servers[0].url, |
892 | token: servers[ 0 ].accessToken, | 892 | token: servers[0].accessToken, |
893 | playlistId: playlistServer1Id, | 893 | playlistId: playlistServer1Id, |
894 | playlistElementId: playlistElementServer1Video5, | 894 | playlistElementId: playlistElementServer1Video5, |
895 | elementAttrs: { | 895 | elementAttrs: { |
@@ -903,62 +903,62 @@ describe('Test video playlists', function () { | |||
903 | const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10) | 903 | const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10) |
904 | const elements: VideoPlaylistElement[] = res.body.data | 904 | const elements: VideoPlaylistElement[] = res.body.data |
905 | 905 | ||
906 | expect(elements[ 0 ].video.name).to.equal('video 3 server 1') | 906 | expect(elements[0].video.name).to.equal('video 3 server 1') |
907 | expect(elements[ 0 ].position).to.equal(1) | 907 | expect(elements[0].position).to.equal(1) |
908 | expect(elements[ 0 ].startTimestamp).to.equal(1) | 908 | expect(elements[0].startTimestamp).to.equal(1) |
909 | expect(elements[ 0 ].stopTimestamp).to.equal(35) | 909 | expect(elements[0].stopTimestamp).to.equal(35) |
910 | 910 | ||
911 | expect(elements[ 5 ].video.name).to.equal('video 4 server 1') | 911 | expect(elements[5].video.name).to.equal('video 4 server 1') |
912 | expect(elements[ 5 ].position).to.equal(6) | 912 | expect(elements[5].position).to.equal(6) |
913 | expect(elements[ 5 ].startTimestamp).to.equal(45) | 913 | expect(elements[5].startTimestamp).to.equal(45) |
914 | expect(elements[ 5 ].stopTimestamp).to.be.null | 914 | expect(elements[5].stopTimestamp).to.be.null |
915 | } | 915 | } |
916 | }) | 916 | }) |
917 | 917 | ||
918 | it('Should check videos existence in my playlist', async function () { | 918 | it('Should check videos existence in my playlist', async function () { |
919 | const videoIds = [ | 919 | const videoIds = [ |
920 | servers[ 0 ].videos[ 0 ].id, | 920 | servers[0].videos[0].id, |
921 | 42000, | 921 | 42000, |
922 | servers[ 0 ].videos[ 3 ].id, | 922 | servers[0].videos[3].id, |
923 | 43000, | 923 | 43000, |
924 | servers[ 0 ].videos[ 4 ].id | 924 | servers[0].videos[4].id |
925 | ] | 925 | ] |
926 | const res = await doVideosExistInMyPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, videoIds) | 926 | const res = await doVideosExistInMyPlaylist(servers[0].url, servers[0].accessToken, videoIds) |
927 | const obj = res.body as VideoExistInPlaylist | 927 | const obj = res.body as VideoExistInPlaylist |
928 | 928 | ||
929 | { | 929 | { |
930 | const elem = obj[ servers[ 0 ].videos[ 0 ].id ] | 930 | const elem = obj[servers[0].videos[0].id] |
931 | expect(elem).to.have.lengthOf(1) | 931 | expect(elem).to.have.lengthOf(1) |
932 | expect(elem[ 0 ].playlistElementId).to.exist | 932 | expect(elem[0].playlistElementId).to.exist |
933 | expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id) | 933 | expect(elem[0].playlistId).to.equal(playlistServer1Id) |
934 | expect(elem[ 0 ].startTimestamp).to.equal(15) | 934 | expect(elem[0].startTimestamp).to.equal(15) |
935 | expect(elem[ 0 ].stopTimestamp).to.equal(28) | 935 | expect(elem[0].stopTimestamp).to.equal(28) |
936 | } | 936 | } |
937 | 937 | ||
938 | { | 938 | { |
939 | const elem = obj[ servers[ 0 ].videos[ 3 ].id ] | 939 | const elem = obj[servers[0].videos[3].id] |
940 | expect(elem).to.have.lengthOf(1) | 940 | expect(elem).to.have.lengthOf(1) |
941 | expect(elem[ 0 ].playlistElementId).to.equal(playlistElementServer1Video4) | 941 | expect(elem[0].playlistElementId).to.equal(playlistElementServer1Video4) |
942 | expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id) | 942 | expect(elem[0].playlistId).to.equal(playlistServer1Id) |
943 | expect(elem[ 0 ].startTimestamp).to.equal(1) | 943 | expect(elem[0].startTimestamp).to.equal(1) |
944 | expect(elem[ 0 ].stopTimestamp).to.equal(35) | 944 | expect(elem[0].stopTimestamp).to.equal(35) |
945 | } | 945 | } |
946 | 946 | ||
947 | { | 947 | { |
948 | const elem = obj[ servers[ 0 ].videos[ 4 ].id ] | 948 | const elem = obj[servers[0].videos[4].id] |
949 | expect(elem).to.have.lengthOf(1) | 949 | expect(elem).to.have.lengthOf(1) |
950 | expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id) | 950 | expect(elem[0].playlistId).to.equal(playlistServer1Id) |
951 | expect(elem[ 0 ].startTimestamp).to.equal(45) | 951 | expect(elem[0].startTimestamp).to.equal(45) |
952 | expect(elem[ 0 ].stopTimestamp).to.equal(null) | 952 | expect(elem[0].stopTimestamp).to.equal(null) |
953 | } | 953 | } |
954 | 954 | ||
955 | expect(obj[ 42000 ]).to.have.lengthOf(0) | 955 | expect(obj[42000]).to.have.lengthOf(0) |
956 | expect(obj[ 43000 ]).to.have.lengthOf(0) | 956 | expect(obj[43000]).to.have.lengthOf(0) |
957 | }) | 957 | }) |
958 | 958 | ||
959 | it('Should automatically update updatedAt field of playlists', async function () { | 959 | it('Should automatically update updatedAt field of playlists', async function () { |
960 | const server = servers[ 1 ] | 960 | const server = servers[1] |
961 | const videoId = servers[ 1 ].videos[ 5 ].id | 961 | const videoId = servers[1].videos[5].id |
962 | 962 | ||
963 | async function getPlaylistNames () { | 963 | async function getPlaylistNames () { |
964 | const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt') | 964 | const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt') |
@@ -974,8 +974,8 @@ describe('Test video playlists', function () { | |||
974 | const element2 = res2.body.videoPlaylistElement.id | 974 | const element2 = res2.body.videoPlaylistElement.id |
975 | 975 | ||
976 | const names1 = await getPlaylistNames() | 976 | const names1 = await getPlaylistNames() |
977 | expect(names1[ 0 ]).to.equal('playlist 3 updated') | 977 | expect(names1[0]).to.equal('playlist 3 updated') |
978 | expect(names1[ 1 ]).to.equal('playlist 2') | 978 | expect(names1[1]).to.equal('playlist 2') |
979 | 979 | ||
980 | await removeVideoFromPlaylist({ | 980 | await removeVideoFromPlaylist({ |
981 | url: server.url, | 981 | url: server.url, |
@@ -985,8 +985,8 @@ describe('Test video playlists', function () { | |||
985 | }) | 985 | }) |
986 | 986 | ||
987 | const names2 = await getPlaylistNames() | 987 | const names2 = await getPlaylistNames() |
988 | expect(names2[ 0 ]).to.equal('playlist 2') | 988 | expect(names2[0]).to.equal('playlist 2') |
989 | expect(names2[ 1 ]).to.equal('playlist 3 updated') | 989 | expect(names2[1]).to.equal('playlist 3 updated') |
990 | 990 | ||
991 | await removeVideoFromPlaylist({ | 991 | await removeVideoFromPlaylist({ |
992 | url: server.url, | 992 | url: server.url, |
@@ -996,23 +996,23 @@ describe('Test video playlists', function () { | |||
996 | }) | 996 | }) |
997 | 997 | ||
998 | const names3 = await getPlaylistNames() | 998 | const names3 = await getPlaylistNames() |
999 | expect(names3[ 0 ]).to.equal('playlist 3 updated') | 999 | expect(names3[0]).to.equal('playlist 3 updated') |
1000 | expect(names3[ 1 ]).to.equal('playlist 2') | 1000 | expect(names3[1]).to.equal('playlist 2') |
1001 | }) | 1001 | }) |
1002 | 1002 | ||
1003 | it('Should delete some elements', async function () { | 1003 | it('Should delete some elements', async function () { |
1004 | this.timeout(30000) | 1004 | this.timeout(30000) |
1005 | 1005 | ||
1006 | await removeVideoFromPlaylist({ | 1006 | await removeVideoFromPlaylist({ |
1007 | url: servers[ 0 ].url, | 1007 | url: servers[0].url, |
1008 | token: servers[ 0 ].accessToken, | 1008 | token: servers[0].accessToken, |
1009 | playlistId: playlistServer1Id, | 1009 | playlistId: playlistServer1Id, |
1010 | playlistElementId: playlistElementServer1Video4 | 1010 | playlistElementId: playlistElementServer1Video4 |
1011 | }) | 1011 | }) |
1012 | 1012 | ||
1013 | await removeVideoFromPlaylist({ | 1013 | await removeVideoFromPlaylist({ |
1014 | url: servers[ 0 ].url, | 1014 | url: servers[0].url, |
1015 | token: servers[ 0 ].accessToken, | 1015 | token: servers[0].accessToken, |
1016 | playlistId: playlistServer1Id, | 1016 | playlistId: playlistServer1Id, |
1017 | playlistElementId: playlistElementNSFW | 1017 | playlistElementId: playlistElementNSFW |
1018 | }) | 1018 | }) |
@@ -1027,17 +1027,17 @@ describe('Test video playlists', function () { | |||
1027 | const elements: VideoPlaylistElement[] = res.body.data | 1027 | const elements: VideoPlaylistElement[] = res.body.data |
1028 | expect(elements).to.have.lengthOf(4) | 1028 | expect(elements).to.have.lengthOf(4) |
1029 | 1029 | ||
1030 | expect(elements[ 0 ].video.name).to.equal('video 0 server 1') | 1030 | expect(elements[0].video.name).to.equal('video 0 server 1') |
1031 | expect(elements[ 0 ].position).to.equal(1) | 1031 | expect(elements[0].position).to.equal(1) |
1032 | 1032 | ||
1033 | expect(elements[ 1 ].video.name).to.equal('video 2 server 3') | 1033 | expect(elements[1].video.name).to.equal('video 2 server 3') |
1034 | expect(elements[ 1 ].position).to.equal(2) | 1034 | expect(elements[1].position).to.equal(2) |
1035 | 1035 | ||
1036 | expect(elements[ 2 ].video.name).to.equal('video 1 server 3') | 1036 | expect(elements[2].video.name).to.equal('video 1 server 3') |
1037 | expect(elements[ 2 ].position).to.equal(3) | 1037 | expect(elements[2].position).to.equal(3) |
1038 | 1038 | ||
1039 | expect(elements[ 3 ].video.name).to.equal('video 4 server 1') | 1039 | expect(elements[3].video.name).to.equal('video 4 server 1') |
1040 | expect(elements[ 3 ].position).to.equal(4) | 1040 | expect(elements[3].position).to.equal(4) |
1041 | } | 1041 | } |
1042 | }) | 1042 | }) |
1043 | 1043 | ||
@@ -1045,12 +1045,12 @@ describe('Test video playlists', function () { | |||
1045 | this.timeout(30000) | 1045 | this.timeout(30000) |
1046 | 1046 | ||
1047 | const res = await createVideoPlaylist({ | 1047 | const res = await createVideoPlaylist({ |
1048 | url: servers[ 0 ].url, | 1048 | url: servers[0].url, |
1049 | token: servers[ 0 ].accessToken, | 1049 | token: servers[0].accessToken, |
1050 | playlistAttrs: { | 1050 | playlistAttrs: { |
1051 | displayName: 'my super public playlist', | 1051 | displayName: 'my super public playlist', |
1052 | privacy: VideoPlaylistPrivacy.PUBLIC, | 1052 | privacy: VideoPlaylistPrivacy.PUBLIC, |
1053 | videoChannelId: servers[ 0 ].videoChannel.id | 1053 | videoChannelId: servers[0].videoChannel.id |
1054 | } | 1054 | } |
1055 | }) | 1055 | }) |
1056 | const videoPlaylistIds = res.body.videoPlaylist | 1056 | const videoPlaylistIds = res.body.videoPlaylist |
@@ -1062,16 +1062,16 @@ describe('Test video playlists', function () { | |||
1062 | } | 1062 | } |
1063 | 1063 | ||
1064 | const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE } | 1064 | const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE } |
1065 | await updateVideoPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs }) | 1065 | await updateVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs }) |
1066 | 1066 | ||
1067 | await waitJobs(servers) | 1067 | await waitJobs(servers) |
1068 | 1068 | ||
1069 | for (const server of [ servers[ 1 ], servers[ 2 ] ]) { | 1069 | for (const server of [ servers[1], servers[2] ]) { |
1070 | await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404) | 1070 | await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404) |
1071 | } | 1071 | } |
1072 | await getVideoPlaylist(servers[ 0 ].url, videoPlaylistIds.uuid, 401) | 1072 | await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, 401) |
1073 | 1073 | ||
1074 | await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistIds.uuid, 200) | 1074 | await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, 200) |
1075 | }) | 1075 | }) |
1076 | }) | 1076 | }) |
1077 | 1077 | ||
@@ -1080,7 +1080,7 @@ describe('Test video playlists', function () { | |||
1080 | it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () { | 1080 | it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () { |
1081 | this.timeout(30000) | 1081 | this.timeout(30000) |
1082 | 1082 | ||
1083 | await deleteVideoPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, playlistServer1Id) | 1083 | await deleteVideoPlaylist(servers[0].url, servers[0].accessToken, playlistServer1Id) |
1084 | 1084 | ||
1085 | await waitJobs(servers) | 1085 | await waitJobs(servers) |
1086 | 1086 | ||
@@ -1103,15 +1103,15 @@ describe('Test video playlists', function () { | |||
1103 | const finder = data => data.find(p => p.displayName === 'my super playlist') | 1103 | const finder = data => data.find(p => p.displayName === 'my super playlist') |
1104 | 1104 | ||
1105 | { | 1105 | { |
1106 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) | 1106 | const res = await getVideoPlaylistsList(servers[2].url, 0, 5) |
1107 | expect(res.body.total).to.equal(3) | 1107 | expect(res.body.total).to.equal(3) |
1108 | expect(finder(res.body.data)).to.not.be.undefined | 1108 | expect(finder(res.body.data)).to.not.be.undefined |
1109 | } | 1109 | } |
1110 | 1110 | ||
1111 | await unfollow(servers[ 2 ].url, servers[ 2 ].accessToken, servers[ 0 ]) | 1111 | await unfollow(servers[2].url, servers[2].accessToken, servers[0]) |
1112 | 1112 | ||
1113 | { | 1113 | { |
1114 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) | 1114 | const res = await getVideoPlaylistsList(servers[2].url, 0, 5) |
1115 | expect(res.body.total).to.equal(1) | 1115 | expect(res.body.total).to.equal(1) |
1116 | 1116 | ||
1117 | expect(finder(res.body.data)).to.be.undefined | 1117 | expect(finder(res.body.data)).to.be.undefined |
@@ -1121,12 +1121,12 @@ describe('Test video playlists', function () { | |||
1121 | it('Should delete a channel and put the associated playlist in private mode', async function () { | 1121 | it('Should delete a channel and put the associated playlist in private mode', async function () { |
1122 | this.timeout(30000) | 1122 | this.timeout(30000) |
1123 | 1123 | ||
1124 | const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'super_channel', displayName: 'super channel' }) | 1124 | const res = await addVideoChannel(servers[0].url, servers[0].accessToken, { name: 'super_channel', displayName: 'super channel' }) |
1125 | const videoChannelId = res.body.videoChannel.id | 1125 | const videoChannelId = res.body.videoChannel.id |
1126 | 1126 | ||
1127 | const res2 = await createVideoPlaylist({ | 1127 | const res2 = await createVideoPlaylist({ |
1128 | url: servers[ 0 ].url, | 1128 | url: servers[0].url, |
1129 | token: servers[ 0 ].accessToken, | 1129 | token: servers[0].accessToken, |
1130 | playlistAttrs: { | 1130 | playlistAttrs: { |
1131 | displayName: 'channel playlist', | 1131 | displayName: 'channel playlist', |
1132 | privacy: VideoPlaylistPrivacy.PUBLIC, | 1132 | privacy: VideoPlaylistPrivacy.PUBLIC, |
@@ -1137,15 +1137,15 @@ describe('Test video playlists', function () { | |||
1137 | 1137 | ||
1138 | await waitJobs(servers) | 1138 | await waitJobs(servers) |
1139 | 1139 | ||
1140 | await deleteVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, 'super_channel') | 1140 | await deleteVideoChannel(servers[0].url, servers[0].accessToken, 'super_channel') |
1141 | 1141 | ||
1142 | await waitJobs(servers) | 1142 | await waitJobs(servers) |
1143 | 1143 | ||
1144 | const res3 = await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistUUID) | 1144 | const res3 = await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistUUID) |
1145 | expect(res3.body.displayName).to.equal('channel playlist') | 1145 | expect(res3.body.displayName).to.equal('channel playlist') |
1146 | expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE) | 1146 | expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE) |
1147 | 1147 | ||
1148 | await getVideoPlaylist(servers[ 1 ].url, videoPlaylistUUID, 404) | 1148 | await getVideoPlaylist(servers[1].url, videoPlaylistUUID, 404) |
1149 | }) | 1149 | }) |
1150 | 1150 | ||
1151 | it('Should delete an account and delete its playlists', async function () { | 1151 | it('Should delete an account and delete its playlists', async function () { |
@@ -1153,20 +1153,20 @@ describe('Test video playlists', function () { | |||
1153 | 1153 | ||
1154 | const user = { username: 'user_1', password: 'password' } | 1154 | const user = { username: 'user_1', password: 'password' } |
1155 | const res = await createUser({ | 1155 | const res = await createUser({ |
1156 | url: servers[ 0 ].url, | 1156 | url: servers[0].url, |
1157 | accessToken: servers[ 0 ].accessToken, | 1157 | accessToken: servers[0].accessToken, |
1158 | username: user.username, | 1158 | username: user.username, |
1159 | password: user.password | 1159 | password: user.password |
1160 | }) | 1160 | }) |
1161 | 1161 | ||
1162 | const userId = res.body.user.id | 1162 | const userId = res.body.user.id |
1163 | const userAccessToken = await userLogin(servers[ 0 ], user) | 1163 | const userAccessToken = await userLogin(servers[0], user) |
1164 | 1164 | ||
1165 | const resChannel = await getMyUserInformation(servers[ 0 ].url, userAccessToken) | 1165 | const resChannel = await getMyUserInformation(servers[0].url, userAccessToken) |
1166 | const userChannel = (resChannel.body as User).videoChannels[ 0 ] | 1166 | const userChannel = (resChannel.body as User).videoChannels[0] |
1167 | 1167 | ||
1168 | await createVideoPlaylist({ | 1168 | await createVideoPlaylist({ |
1169 | url: servers[ 0 ].url, | 1169 | url: servers[0].url, |
1170 | token: userAccessToken, | 1170 | token: userAccessToken, |
1171 | playlistAttrs: { | 1171 | playlistAttrs: { |
1172 | displayName: 'playlist to be deleted', | 1172 | displayName: 'playlist to be deleted', |
@@ -1180,17 +1180,17 @@ describe('Test video playlists', function () { | |||
1180 | const finder = data => data.find(p => p.displayName === 'playlist to be deleted') | 1180 | const finder = data => data.find(p => p.displayName === 'playlist to be deleted') |
1181 | 1181 | ||
1182 | { | 1182 | { |
1183 | for (const server of [ servers[ 0 ], servers[ 1 ] ]) { | 1183 | for (const server of [ servers[0], servers[1] ]) { |
1184 | const res = await getVideoPlaylistsList(server.url, 0, 15) | 1184 | const res = await getVideoPlaylistsList(server.url, 0, 15) |
1185 | expect(finder(res.body.data)).to.not.be.undefined | 1185 | expect(finder(res.body.data)).to.not.be.undefined |
1186 | } | 1186 | } |
1187 | } | 1187 | } |
1188 | 1188 | ||
1189 | await removeUser(servers[ 0 ].url, userId, servers[ 0 ].accessToken) | 1189 | await removeUser(servers[0].url, userId, servers[0].accessToken) |
1190 | await waitJobs(servers) | 1190 | await waitJobs(servers) |
1191 | 1191 | ||
1192 | { | 1192 | { |
1193 | for (const server of [ servers[ 0 ], servers[ 1 ] ]) { | 1193 | for (const server of [ servers[0], servers[1] ]) { |
1194 | const res = await getVideoPlaylistsList(server.url, 0, 15) | 1194 | const res = await getVideoPlaylistsList(server.url, 0, 15) |
1195 | expect(finder(res.body.data)).to.be.undefined | 1195 | expect(finder(res.body.data)).to.be.undefined |
1196 | } | 1196 | } |
diff --git a/server/tests/api/videos/video-privacy.ts b/server/tests/api/videos/video-privacy.ts index e630ca84a..4bbbb90f3 100644 --- a/server/tests/api/videos/video-privacy.ts +++ b/server/tests/api/videos/video-privacy.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -6,7 +6,8 @@ import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enu | |||
6 | import { | 6 | import { |
7 | cleanupTests, | 7 | cleanupTests, |
8 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
9 | getVideosList, getVideosListWithToken, | 9 | getVideosList, |
10 | getVideosListWithToken, | ||
10 | ServerInfo, | 11 | ServerInfo, |
11 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
12 | uploadVideo | 13 | uploadVideo |
@@ -110,7 +111,7 @@ describe('Test video privacy', function () { | |||
110 | username: 'hello', | 111 | username: 'hello', |
111 | password: 'super password' | 112 | password: 'super password' |
112 | } | 113 | } |
113 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 114 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
114 | 115 | ||
115 | anotherUserToken = await userLogin(servers[0], user) | 116 | anotherUserToken = await userLogin(servers[0], user) |
116 | await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, 403) | 117 | await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, 403) |
@@ -174,7 +175,7 @@ describe('Test video privacy', function () { | |||
174 | privacy: VideoPrivacy.PUBLIC | 175 | privacy: VideoPrivacy.PUBLIC |
175 | } | 176 | } |
176 | 177 | ||
177 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, privateVideoId, attribute) | 178 | await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute) |
178 | } | 179 | } |
179 | 180 | ||
180 | { | 181 | { |
@@ -182,7 +183,7 @@ describe('Test video privacy', function () { | |||
182 | name: 'internal video becomes public', | 183 | name: 'internal video becomes public', |
183 | privacy: VideoPrivacy.PUBLIC | 184 | privacy: VideoPrivacy.PUBLIC |
184 | } | 185 | } |
185 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, internalVideoId, attribute) | 186 | await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, attribute) |
186 | } | 187 | } |
187 | 188 | ||
188 | await waitJobs(servers) | 189 | await waitJobs(servers) |
diff --git a/server/tests/api/videos/video-schedule-update.ts b/server/tests/api/videos/video-schedule-update.ts index 65a8eafb8..204f43611 100644 --- a/server/tests/api/videos/video-schedule-update.ts +++ b/server/tests/api/videos/video-schedule-update.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -10,7 +10,6 @@ import { | |||
10 | getMyVideos, | 10 | getMyVideos, |
11 | getVideosList, | 11 | getVideosList, |
12 | getVideoWithToken, | 12 | getVideoWithToken, |
13 | killallServers, | ||
14 | ServerInfo, | 13 | ServerInfo, |
15 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
16 | updateVideo, | 15 | updateVideo, |
diff --git a/server/tests/api/videos/video-transcoder.ts b/server/tests/api/videos/video-transcoder.ts index 4be74901a..3e73ccbfa 100644 --- a/server/tests/api/videos/video-transcoder.ts +++ b/server/tests/api/videos/video-transcoder.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -11,6 +11,7 @@ import { | |||
11 | doubleFollow, | 11 | doubleFollow, |
12 | flushAndRunMultipleServers, | 12 | flushAndRunMultipleServers, |
13 | generateHighBitrateVideo, | 13 | generateHighBitrateVideo, |
14 | generateVideoWithFramerate, | ||
14 | getMyVideos, | 15 | getMyVideos, |
15 | getVideo, | 16 | getVideo, |
16 | getVideosList, | 17 | getVideosList, |
@@ -55,19 +56,19 @@ describe('Test video transcoding', function () { | |||
55 | 56 | ||
56 | for (const server of servers) { | 57 | for (const server of servers) { |
57 | const res = await getVideosList(server.url) | 58 | const res = await getVideosList(server.url) |
58 | const video = res.body.data[ 0 ] | 59 | const video = res.body.data[0] |
59 | 60 | ||
60 | const res2 = await getVideo(server.url, video.id) | 61 | const res2 = await getVideo(server.url, video.id) |
61 | const videoDetails = res2.body | 62 | const videoDetails = res2.body |
62 | expect(videoDetails.files).to.have.lengthOf(1) | 63 | expect(videoDetails.files).to.have.lengthOf(1) |
63 | 64 | ||
64 | const magnetUri = videoDetails.files[ 0 ].magnetUri | 65 | const magnetUri = videoDetails.files[0].magnetUri |
65 | expect(magnetUri).to.match(/\.webm/) | 66 | expect(magnetUri).to.match(/\.webm/) |
66 | 67 | ||
67 | const torrent = await webtorrentAdd(magnetUri, true) | 68 | const torrent = await webtorrentAdd(magnetUri, true) |
68 | expect(torrent.files).to.be.an('array') | 69 | expect(torrent.files).to.be.an('array') |
69 | expect(torrent.files.length).to.equal(1) | 70 | expect(torrent.files.length).to.equal(1) |
70 | expect(torrent.files[ 0 ].path).match(/\.webm$/) | 71 | expect(torrent.files[0].path).match(/\.webm$/) |
71 | } | 72 | } |
72 | }) | 73 | }) |
73 | 74 | ||
@@ -92,13 +93,13 @@ describe('Test video transcoding', function () { | |||
92 | 93 | ||
93 | expect(videoDetails.files).to.have.lengthOf(4) | 94 | expect(videoDetails.files).to.have.lengthOf(4) |
94 | 95 | ||
95 | const magnetUri = videoDetails.files[ 0 ].magnetUri | 96 | const magnetUri = videoDetails.files[0].magnetUri |
96 | expect(magnetUri).to.match(/\.mp4/) | 97 | expect(magnetUri).to.match(/\.mp4/) |
97 | 98 | ||
98 | const torrent = await webtorrentAdd(magnetUri, true) | 99 | const torrent = await webtorrentAdd(magnetUri, true) |
99 | expect(torrent.files).to.be.an('array') | 100 | expect(torrent.files).to.be.an('array') |
100 | expect(torrent.files.length).to.equal(1) | 101 | expect(torrent.files.length).to.equal(1) |
101 | expect(torrent.files[ 0 ].path).match(/\.mp4$/) | 102 | expect(torrent.files[0].path).match(/\.mp4$/) |
102 | } | 103 | } |
103 | }) | 104 | }) |
104 | 105 | ||
@@ -126,8 +127,8 @@ describe('Test video transcoding', function () { | |||
126 | const probe = await audio.get(path) | 127 | const probe = await audio.get(path) |
127 | 128 | ||
128 | if (probe.audioStream) { | 129 | if (probe.audioStream) { |
129 | expect(probe.audioStream[ 'codec_name' ]).to.be.equal('aac') | 130 | expect(probe.audioStream['codec_name']).to.be.equal('aac') |
130 | expect(probe.audioStream[ 'bit_rate' ]).to.be.at.most(384 * 8000) | 131 | expect(probe.audioStream['bit_rate']).to.be.at.most(384 * 8000) |
131 | } else { | 132 | } else { |
132 | this.fail('Could not retrieve the audio stream on ' + probe.absolutePath) | 133 | this.fail('Could not retrieve the audio stream on ' + probe.absolutePath) |
133 | } | 134 | } |
@@ -211,10 +212,10 @@ describe('Test video transcoding', function () { | |||
211 | const videoDetails: VideoDetails = res2.body | 212 | const videoDetails: VideoDetails = res2.body |
212 | 213 | ||
213 | expect(videoDetails.files).to.have.lengthOf(4) | 214 | expect(videoDetails.files).to.have.lengthOf(4) |
214 | expect(videoDetails.files[ 0 ].fps).to.be.above(58).and.below(62) | 215 | expect(videoDetails.files[0].fps).to.be.above(58).and.below(62) |
215 | expect(videoDetails.files[ 1 ].fps).to.be.below(31) | 216 | expect(videoDetails.files[1].fps).to.be.below(31) |
216 | expect(videoDetails.files[ 2 ].fps).to.be.below(31) | 217 | expect(videoDetails.files[2].fps).to.be.below(31) |
217 | expect(videoDetails.files[ 3 ].fps).to.be.below(31) | 218 | expect(videoDetails.files[3].fps).to.be.below(31) |
218 | 219 | ||
219 | for (const resolution of [ '240', '360', '480' ]) { | 220 | for (const resolution of [ '240', '360', '480' ]) { |
220 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') | 221 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') |
@@ -240,11 +241,11 @@ describe('Test video transcoding', function () { | |||
240 | fixture: 'video_short1.webm', | 241 | fixture: 'video_short1.webm', |
241 | waitTranscoding: true | 242 | waitTranscoding: true |
242 | } | 243 | } |
243 | const resVideo = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributes) | 244 | const resVideo = await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes) |
244 | const videoId = resVideo.body.video.uuid | 245 | const videoId = resVideo.body.video.uuid |
245 | 246 | ||
246 | // Should be in transcode state | 247 | // Should be in transcode state |
247 | const { body } = await getVideo(servers[ 1 ].url, videoId) | 248 | const { body } = await getVideo(servers[1].url, videoId) |
248 | expect(body.name).to.equal('waiting video') | 249 | expect(body.name).to.equal('waiting video') |
249 | expect(body.state.id).to.equal(VideoState.TO_TRANSCODE) | 250 | expect(body.state.id).to.equal(VideoState.TO_TRANSCODE) |
250 | expect(body.state.label).to.equal('To transcode') | 251 | expect(body.state.label).to.equal('To transcode') |
@@ -310,7 +311,7 @@ describe('Test video transcoding', function () { | |||
310 | 311 | ||
311 | const video = res.body.data.find(v => v.name === videoAttributes.name) | 312 | const video = res.body.data.find(v => v.name === videoAttributes.name) |
312 | 313 | ||
313 | for (const resolution of ['240', '360', '480', '720', '1080']) { | 314 | for (const resolution of [ '240', '360', '480', '720', '1080' ]) { |
314 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') | 315 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') |
315 | const bitrate = await getVideoFileBitrate(path) | 316 | const bitrate = await getVideoFileBitrate(path) |
316 | const fps = await getVideoFileFPS(path) | 317 | const fps = await getVideoFileFPS(path) |
@@ -340,7 +341,7 @@ describe('Test video transcoding', function () { | |||
340 | fixture | 341 | fixture |
341 | } | 342 | } |
342 | 343 | ||
343 | await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributes) | 344 | await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes) |
344 | 345 | ||
345 | await waitJobs(servers) | 346 | await waitJobs(servers) |
346 | 347 | ||
@@ -353,7 +354,7 @@ describe('Test video transcoding', function () { | |||
353 | 354 | ||
354 | expect(videoDetails.files).to.have.lengthOf(4) | 355 | expect(videoDetails.files).to.have.lengthOf(4) |
355 | 356 | ||
356 | const magnetUri = videoDetails.files[ 0 ].magnetUri | 357 | const magnetUri = videoDetails.files[0].magnetUri |
357 | expect(magnetUri).to.contain('.mp4') | 358 | expect(magnetUri).to.contain('.mp4') |
358 | } | 359 | } |
359 | } | 360 | } |
@@ -370,7 +371,7 @@ describe('Test video transcoding', function () { | |||
370 | this.timeout(60000) | 371 | this.timeout(60000) |
371 | 372 | ||
372 | const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } | 373 | const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } |
373 | await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg) | 374 | await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg) |
374 | 375 | ||
375 | await waitJobs(servers) | 376 | await waitJobs(servers) |
376 | 377 | ||
@@ -386,7 +387,7 @@ describe('Test video transcoding', function () { | |||
386 | await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) | 387 | await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) |
387 | await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) | 388 | await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) |
388 | 389 | ||
389 | const magnetUri = videoDetails.files[ 0 ].magnetUri | 390 | const magnetUri = videoDetails.files[0].magnetUri |
390 | expect(magnetUri).to.contain('.mp4') | 391 | expect(magnetUri).to.contain('.mp4') |
391 | } | 392 | } |
392 | }) | 393 | }) |
@@ -395,7 +396,7 @@ describe('Test video transcoding', function () { | |||
395 | this.timeout(60000) | 396 | this.timeout(60000) |
396 | 397 | ||
397 | const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' } | 398 | const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' } |
398 | await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg) | 399 | await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg) |
399 | 400 | ||
400 | await waitJobs(servers) | 401 | await waitJobs(servers) |
401 | 402 | ||
@@ -411,11 +412,52 @@ describe('Test video transcoding', function () { | |||
411 | await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) | 412 | await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) |
412 | await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) | 413 | await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) |
413 | 414 | ||
414 | const magnetUri = videoDetails.files[ 0 ].magnetUri | 415 | const magnetUri = videoDetails.files[0].magnetUri |
415 | expect(magnetUri).to.contain('.mp4') | 416 | expect(magnetUri).to.contain('.mp4') |
416 | } | 417 | } |
417 | }) | 418 | }) |
418 | 419 | ||
420 | it('Should downscale to the closest divisor standard framerate', async function () { | ||
421 | this.timeout(160000) | ||
422 | |||
423 | let tempFixturePath: string | ||
424 | |||
425 | { | ||
426 | tempFixturePath = await generateVideoWithFramerate(59) | ||
427 | |||
428 | const fps = await getVideoFileFPS(tempFixturePath) | ||
429 | expect(fps).to.be.equal(59) | ||
430 | } | ||
431 | |||
432 | const videoAttributes = { | ||
433 | name: '59fps video', | ||
434 | description: '59fps video', | ||
435 | fixture: tempFixturePath | ||
436 | } | ||
437 | |||
438 | await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes) | ||
439 | |||
440 | await waitJobs(servers) | ||
441 | |||
442 | for (const server of servers) { | ||
443 | const res = await getVideosList(server.url) | ||
444 | |||
445 | const video = res.body.data.find(v => v.name === videoAttributes.name) | ||
446 | |||
447 | { | ||
448 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4') | ||
449 | const fps = await getVideoFileFPS(path) | ||
450 | expect(fps).to.be.equal(25) | ||
451 | } | ||
452 | |||
453 | { | ||
454 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-720.mp4') | ||
455 | const fps = await getVideoFileFPS(path) | ||
456 | expect(fps).to.be.equal(59) | ||
457 | } | ||
458 | } | ||
459 | }) | ||
460 | |||
419 | after(async function () { | 461 | after(async function () { |
420 | await cleanupTests(servers) | 462 | await cleanupTests(servers) |
421 | }) | 463 | }) |
diff --git a/server/tests/api/videos/videos-filter.ts b/server/tests/api/videos/videos-filter.ts index e1e65260f..95e12e43c 100644 --- a/server/tests/api/videos/videos-filter.ts +++ b/server/tests/api/videos/videos-filter.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -7,8 +7,6 @@ import { | |||
7 | createUser, | 7 | createUser, |
8 | doubleFollow, | 8 | doubleFollow, |
9 | flushAndRunMultipleServers, | 9 | flushAndRunMultipleServers, |
10 | flushTests, | ||
11 | killallServers, | ||
12 | makeGetRequest, | 10 | makeGetRequest, |
13 | ServerInfo, | 11 | ServerInfo, |
14 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
@@ -98,7 +96,7 @@ describe('Test videos filter validator', function () { | |||
98 | const namesResults = await getVideosNames(server, server.accessToken, 'local') | 96 | const namesResults = await getVideosNames(server, server.accessToken, 'local') |
99 | for (const names of namesResults) { | 97 | for (const names of namesResults) { |
100 | expect(names).to.have.lengthOf(1) | 98 | expect(names).to.have.lengthOf(1) |
101 | expect(names[ 0 ]).to.equal('public ' + server.serverNumber) | 99 | expect(names[0]).to.equal('public ' + server.serverNumber) |
102 | } | 100 | } |
103 | } | 101 | } |
104 | }) | 102 | }) |
@@ -111,9 +109,9 @@ describe('Test videos filter validator', function () { | |||
111 | for (const names of namesResults) { | 109 | for (const names of namesResults) { |
112 | expect(names).to.have.lengthOf(3) | 110 | expect(names).to.have.lengthOf(3) |
113 | 111 | ||
114 | expect(names[ 0 ]).to.equal('public ' + server.serverNumber) | 112 | expect(names[0]).to.equal('public ' + server.serverNumber) |
115 | expect(names[ 1 ]).to.equal('unlisted ' + server.serverNumber) | 113 | expect(names[1]).to.equal('unlisted ' + server.serverNumber) |
116 | expect(names[ 2 ]).to.equal('private ' + server.serverNumber) | 114 | expect(names[2]).to.equal('private ' + server.serverNumber) |
117 | } | 115 | } |
118 | } | 116 | } |
119 | } | 117 | } |
diff --git a/server/tests/api/videos/videos-history.ts b/server/tests/api/videos/videos-history.ts index c7e55c1ab..6f90e9a57 100644 --- a/server/tests/api/videos/videos-history.ts +++ b/server/tests/api/videos/videos-history.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/videos/videos-overview.ts b/server/tests/api/videos/videos-overview.ts index 975a5c87a..ca08ab5b1 100644 --- a/server/tests/api/videos/videos-overview.ts +++ b/server/tests/api/videos/videos-overview.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/videos/videos-views-cleaner.ts b/server/tests/api/videos/videos-views-cleaner.ts index fbddd40f4..d063d7973 100644 --- a/server/tests/api/videos/videos-views-cleaner.ts +++ b/server/tests/api/videos/videos-views-cleaner.ts | |||
@@ -1,20 +1,22 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | cleanupTests, | ||
7 | closeAllSequelize, | ||
8 | countVideoViewsOf, | ||
9 | doubleFollow, | ||
6 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
7 | flushTests, | ||
8 | killallServers, | 11 | killallServers, |
9 | reRunServer, | 12 | reRunServer, |
10 | flushAndRunServer, | ||
11 | ServerInfo, | 13 | ServerInfo, |
12 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
13 | uploadVideo, uploadVideoAndGetId, viewVideo, wait, countVideoViewsOf, doubleFollow, waitJobs, cleanupTests, closeAllSequelize | 15 | uploadVideoAndGetId, |
16 | viewVideo, | ||
17 | wait, | ||
18 | waitJobs | ||
14 | } from '../../../../shared/extra-utils' | 19 | } from '../../../../shared/extra-utils' |
15 | import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews' | ||
16 | import { VideosOverview } from '../../../../shared/models/overviews' | ||
17 | import { listMyVideosHistory } from '../../../../shared/extra-utils/videos/video-history' | ||
18 | 20 | ||
19 | const expect = chai.expect | 21 | const expect = chai.expect |
20 | 22 | ||
diff --git a/server/tests/cli/create-import-video-file-job.ts b/server/tests/cli/create-import-video-file-job.ts index aca3216bb..dac049fe4 100644 --- a/server/tests/cli/create-import-video-file-job.ts +++ b/server/tests/cli/create-import-video-file-job.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -71,7 +71,7 @@ describe('Test create import video jobs', function () { | |||
71 | const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body | 71 | const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body |
72 | 72 | ||
73 | expect(videoDetail.files).to.have.lengthOf(2) | 73 | expect(videoDetail.files).to.have.lengthOf(2) |
74 | const [originalVideo, transcodedVideo] = videoDetail.files | 74 | const [ originalVideo, transcodedVideo ] = videoDetail.files |
75 | assertVideoProperties(originalVideo, 720, 'webm', 218910) | 75 | assertVideoProperties(originalVideo, 720, 'webm', 218910) |
76 | assertVideoProperties(transcodedVideo, 480, 'webm', 69217) | 76 | assertVideoProperties(transcodedVideo, 480, 'webm', 69217) |
77 | 77 | ||
@@ -95,7 +95,7 @@ describe('Test create import video jobs', function () { | |||
95 | const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body | 95 | const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body |
96 | 96 | ||
97 | expect(videoDetail.files).to.have.lengthOf(4) | 97 | expect(videoDetail.files).to.have.lengthOf(4) |
98 | const [originalVideo, transcodedVideo420, transcodedVideo320, transcodedVideo240] = videoDetail.files | 98 | const [ originalVideo, transcodedVideo420, transcodedVideo320, transcodedVideo240 ] = videoDetail.files |
99 | assertVideoProperties(originalVideo, 720, 'ogv', 140849) | 99 | assertVideoProperties(originalVideo, 720, 'ogv', 140849) |
100 | assertVideoProperties(transcodedVideo420, 480, 'mp4') | 100 | assertVideoProperties(transcodedVideo420, 480, 'mp4') |
101 | assertVideoProperties(transcodedVideo320, 360, 'mp4') | 101 | assertVideoProperties(transcodedVideo320, 360, 'mp4') |
diff --git a/server/tests/cli/create-transcoding-job.ts b/server/tests/cli/create-transcoding-job.ts index 7897ff1b3..997a9a1fd 100644 --- a/server/tests/cli/create-transcoding-job.ts +++ b/server/tests/cli/create-transcoding-job.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -8,14 +8,13 @@ import { | |||
8 | doubleFollow, | 8 | doubleFollow, |
9 | execCLI, | 9 | execCLI, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
11 | flushTests, | ||
12 | getEnvCli, | 11 | getEnvCli, |
13 | getVideo, | 12 | getVideo, |
14 | getVideosList, | 13 | getVideosList, |
15 | killallServers, | ||
16 | ServerInfo, | 14 | ServerInfo, |
17 | setAccessTokensToServers, updateCustomSubConfig, | 15 | setAccessTokensToServers, |
18 | uploadVideo, wait | 16 | updateCustomSubConfig, |
17 | uploadVideo | ||
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 | 20 | ||
@@ -23,7 +22,7 @@ const expect = chai.expect | |||
23 | 22 | ||
24 | describe('Test create transcoding jobs', function () { | 23 | describe('Test create transcoding jobs', function () { |
25 | let servers: ServerInfo[] = [] | 24 | let servers: ServerInfo[] = [] |
26 | let videosUUID: string[] = [] | 25 | const videosUUID: string[] = [] |
27 | 26 | ||
28 | const config = { | 27 | const config = { |
29 | transcoding: { | 28 | transcoding: { |
@@ -54,7 +53,7 @@ describe('Test create transcoding jobs', function () { | |||
54 | await doubleFollow(servers[0], servers[1]) | 53 | await doubleFollow(servers[0], servers[1]) |
55 | 54 | ||
56 | for (let i = 1; i <= 5; i++) { | 55 | for (let i = 1; i <= 5; i++) { |
57 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video' + i }) | 56 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' + i }) |
58 | videosUUID.push(res.body.video.uuid) | 57 | videosUUID.push(res.body.video.uuid) |
59 | } | 58 | } |
60 | 59 | ||
@@ -90,7 +89,7 @@ describe('Test create transcoding jobs', function () { | |||
90 | const res = await getVideosList(server.url) | 89 | const res = await getVideosList(server.url) |
91 | const videos = res.body.data | 90 | const videos = res.body.data |
92 | 91 | ||
93 | let infoHashes: { [ id: number ]: string } | 92 | let infoHashes: { [id: number]: string } |
94 | 93 | ||
95 | for (const video of videos) { | 94 | for (const video of videos) { |
96 | const res2 = await getVideo(server.url, video.uuid) | 95 | const res2 = await getVideo(server.url, video.uuid) |
diff --git a/server/tests/cli/optimize-old-videos.ts b/server/tests/cli/optimize-old-videos.ts index de5d672f5..e2e13598f 100644 --- a/server/tests/cli/optimize-old-videos.ts +++ b/server/tests/cli/optimize-old-videos.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -28,7 +28,9 @@ const expect = chai.expect | |||
28 | 28 | ||
29 | describe('Test optimize old videos', function () { | 29 | describe('Test optimize old videos', function () { |
30 | let servers: ServerInfo[] = [] | 30 | let servers: ServerInfo[] = [] |
31 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
31 | let video1UUID: string | 32 | let video1UUID: string |
33 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
32 | let video2UUID: string | 34 | let video2UUID: string |
33 | 35 | ||
34 | before(async function () { | 36 | before(async function () { |
diff --git a/server/tests/cli/peertube.ts b/server/tests/cli/peertube.ts index b8c0b1f79..27fbde02d 100644 --- a/server/tests/cli/peertube.ts +++ b/server/tests/cli/peertube.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
@@ -7,14 +7,17 @@ import { | |||
7 | buildAbsoluteFixturePath, | 7 | buildAbsoluteFixturePath, |
8 | cleanupTests, | 8 | cleanupTests, |
9 | createUser, | 9 | createUser, |
10 | doubleFollow, | ||
10 | execCLI, | 11 | execCLI, |
11 | flushAndRunServer, | 12 | flushAndRunServer, |
12 | getEnvCli, | 13 | getEnvCli, |
14 | getLocalIdByUUID, | ||
13 | getVideo, | 15 | getVideo, |
14 | getVideosList, | 16 | getVideosList, |
15 | getVideosListWithToken, removeVideo, | 17 | removeVideo, |
16 | ServerInfo, | 18 | ServerInfo, |
17 | setAccessTokensToServers, | 19 | setAccessTokensToServers, |
20 | uploadVideoAndGetId, | ||
18 | userLogin, | 21 | userLogin, |
19 | waitJobs | 22 | waitJobs |
20 | } from '../../../shared/extra-utils' | 23 | } from '../../../shared/extra-utils' |
@@ -101,7 +104,7 @@ describe('Test CLI wrapper', function () { | |||
101 | 104 | ||
102 | const videos: Video[] = res.body.data | 105 | const videos: Video[] = res.body.data |
103 | 106 | ||
104 | const video: VideoDetails = (await getVideo(server.url, videos[ 0 ].uuid)).body | 107 | const video: VideoDetails = (await getVideo(server.url, videos[0].uuid)).body |
105 | 108 | ||
106 | expect(video.name).to.equal('test upload') | 109 | expect(video.name).to.equal('test upload') |
107 | expect(video.support).to.equal('support_text') | 110 | expect(video.support).to.equal('support_text') |
@@ -210,6 +213,81 @@ describe('Test CLI wrapper', function () { | |||
210 | }) | 213 | }) |
211 | }) | 214 | }) |
212 | 215 | ||
216 | describe('Manage video redundancies', function () { | ||
217 | let anotherServer: ServerInfo | ||
218 | let video1Server2: number | ||
219 | let servers: ServerInfo[] | ||
220 | |||
221 | before(async function () { | ||
222 | this.timeout(120000) | ||
223 | |||
224 | anotherServer = await flushAndRunServer(2) | ||
225 | await setAccessTokensToServers([ anotherServer ]) | ||
226 | |||
227 | await doubleFollow(server, anotherServer) | ||
228 | |||
229 | servers = [ server, anotherServer ] | ||
230 | await waitJobs(servers) | ||
231 | |||
232 | const uuid = (await uploadVideoAndGetId({ server: anotherServer, videoName: 'super video' })).uuid | ||
233 | await waitJobs(servers) | ||
234 | |||
235 | video1Server2 = await getLocalIdByUUID(server.url, uuid) | ||
236 | }) | ||
237 | |||
238 | it('Should add a redundancy', async function () { | ||
239 | this.timeout(60000) | ||
240 | |||
241 | const env = getEnvCli(server) | ||
242 | |||
243 | const params = `add --video ${video1Server2}` | ||
244 | |||
245 | await execCLI(`${env} ${cmd} redundancy ${params}`) | ||
246 | |||
247 | await waitJobs(servers) | ||
248 | }) | ||
249 | |||
250 | it('Should list redundancies', async function () { | ||
251 | this.timeout(60000) | ||
252 | |||
253 | { | ||
254 | const env = getEnvCli(server) | ||
255 | |||
256 | const params = 'list-my-redundancies' | ||
257 | const stdout = await execCLI(`${env} ${cmd} redundancy ${params}`) | ||
258 | |||
259 | expect(stdout).to.contain('super video') | ||
260 | expect(stdout).to.contain(`localhost:${server.port}`) | ||
261 | } | ||
262 | }) | ||
263 | |||
264 | it('Should remove a redundancy', async function () { | ||
265 | this.timeout(60000) | ||
266 | |||
267 | const env = getEnvCli(server) | ||
268 | |||
269 | const params = `remove --video ${video1Server2}` | ||
270 | |||
271 | await execCLI(`${env} ${cmd} redundancy ${params}`) | ||
272 | |||
273 | await waitJobs(servers) | ||
274 | |||
275 | { | ||
276 | const env = getEnvCli(server) | ||
277 | const params = 'list-my-redundancies' | ||
278 | const stdout = await execCLI(`${env} ${cmd} redundancy ${params}`) | ||
279 | |||
280 | expect(stdout).to.not.contain('super video') | ||
281 | } | ||
282 | }) | ||
283 | |||
284 | after(async function () { | ||
285 | this.timeout(10000) | ||
286 | |||
287 | await cleanupTests([ anotherServer ]) | ||
288 | }) | ||
289 | }) | ||
290 | |||
213 | after(async function () { | 291 | after(async function () { |
214 | this.timeout(10000) | 292 | this.timeout(10000) |
215 | 293 | ||
diff --git a/server/tests/cli/plugins.ts b/server/tests/cli/plugins.ts index a5257d671..7f19f14b7 100644 --- a/server/tests/cli/plugins.ts +++ b/server/tests/cli/plugins.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
diff --git a/server/tests/cli/prune-storage.ts b/server/tests/cli/prune-storage.ts index 144e67c44..304c8ca56 100644 --- a/server/tests/cli/prune-storage.ts +++ b/server/tests/cli/prune-storage.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -11,9 +11,11 @@ import { | |||
11 | execCLI, | 11 | execCLI, |
12 | flushAndRunMultipleServers, | 12 | flushAndRunMultipleServers, |
13 | getAccount, | 13 | getAccount, |
14 | getEnvCli, makeGetRequest, makeRawRequest, | 14 | getEnvCli, |
15 | makeGetRequest, | ||
15 | ServerInfo, | 16 | ServerInfo, |
16 | setAccessTokensToServers, setDefaultVideoChannel, | 17 | setAccessTokensToServers, |
18 | setDefaultVideoChannel, | ||
17 | updateMyAvatar, | 19 | updateMyAvatar, |
18 | uploadVideo, | 20 | uploadVideo, |
19 | wait | 21 | wait |
@@ -22,7 +24,6 @@ import { Account, VideoPlaylistPrivacy } from '../../../shared/models' | |||
22 | import { createFile, readdir } from 'fs-extra' | 24 | import { createFile, readdir } from 'fs-extra' |
23 | import * as uuidv4 from 'uuid/v4' | 25 | import * as uuidv4 from 'uuid/v4' |
24 | import { join } from 'path' | 26 | import { join } from 'path' |
25 | import * as request from 'supertest' | ||
26 | 27 | ||
27 | const expect = chai.expect | 28 | const expect = chai.expect |
28 | 29 | ||
@@ -61,7 +62,7 @@ async function assertCountAreOkay (servers: ServerInfo[]) { | |||
61 | 62 | ||
62 | describe('Test prune storage scripts', function () { | 63 | describe('Test prune storage scripts', function () { |
63 | let servers: ServerInfo[] | 64 | let servers: ServerInfo[] |
64 | const badNames: { [ directory: string ]: string[] } = {} | 65 | const badNames: { [directory: string]: string[] } = {} |
65 | 66 | ||
66 | before(async function () { | 67 | before(async function () { |
67 | this.timeout(120000) | 68 | this.timeout(120000) |
@@ -92,20 +93,20 @@ describe('Test prune storage scripts', function () { | |||
92 | 93 | ||
93 | // Lazy load the remote avatar | 94 | // Lazy load the remote avatar |
94 | { | 95 | { |
95 | const res = await getAccount(servers[ 0 ].url, 'root@localhost:' + servers[ 1 ].port) | 96 | const res = await getAccount(servers[0].url, 'root@localhost:' + servers[1].port) |
96 | const account: Account = res.body | 97 | const account: Account = res.body |
97 | await makeGetRequest({ | 98 | await makeGetRequest({ |
98 | url: servers[ 0 ].url, | 99 | url: servers[0].url, |
99 | path: account.avatar.path, | 100 | path: account.avatar.path, |
100 | statusCodeExpected: 200 | 101 | statusCodeExpected: 200 |
101 | }) | 102 | }) |
102 | } | 103 | } |
103 | 104 | ||
104 | { | 105 | { |
105 | const res = await getAccount(servers[ 1 ].url, 'root@localhost:' + servers[ 0 ].port) | 106 | const res = await getAccount(servers[1].url, 'root@localhost:' + servers[0].port) |
106 | const account: Account = res.body | 107 | const account: Account = res.body |
107 | await makeGetRequest({ | 108 | await makeGetRequest({ |
108 | url: servers[ 1 ].url, | 109 | url: servers[1].url, |
109 | path: account.avatar.path, | 110 | path: account.avatar.path, |
110 | statusCodeExpected: 200 | 111 | statusCodeExpected: 200 |
111 | }) | 112 | }) |
diff --git a/server/tests/cli/update-host.ts b/server/tests/cli/update-host.ts index 55c43b32f..2070f16f5 100644 --- a/server/tests/cli/update-host.ts +++ b/server/tests/cli/update-host.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
diff --git a/server/tests/client.ts b/server/tests/client.ts index 778dcd08e..d61724e51 100644 --- a/server/tests/client.ts +++ b/server/tests/client.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index 437470327..4510177cc 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -51,7 +51,7 @@ describe('Test syndication feeds', () => { | |||
51 | 51 | ||
52 | { | 52 | { |
53 | const attr = { username: 'john', password: 'password' } | 53 | const attr = { username: 'john', password: 'password' } |
54 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: attr.username, password: attr.password }) | 54 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: attr.username, password: attr.password }) |
55 | userAccessToken = await userLogin(servers[0], attr) | 55 | userAccessToken = await userLogin(servers[0], attr) |
56 | 56 | ||
57 | const res = await getMyUserInformation(servers[0].url, userAccessToken) | 57 | const res = await getMyUserInformation(servers[0].url, userAccessToken) |
@@ -61,7 +61,7 @@ describe('Test syndication feeds', () => { | |||
61 | } | 61 | } |
62 | 62 | ||
63 | { | 63 | { |
64 | await uploadVideo(servers[ 0 ].url, userAccessToken, { name: 'user video' }) | 64 | await uploadVideo(servers[0].url, userAccessToken, { name: 'user video' }) |
65 | } | 65 | } |
66 | 66 | ||
67 | { | 67 | { |
@@ -70,11 +70,11 @@ describe('Test syndication feeds', () => { | |||
70 | description: 'my super description for server 1', | 70 | description: 'my super description for server 1', |
71 | fixture: 'video_short.webm' | 71 | fixture: 'video_short.webm' |
72 | } | 72 | } |
73 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) | 73 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes) |
74 | const videoId = res.body.video.id | 74 | const videoId = res.body.video.id |
75 | 75 | ||
76 | await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, 'super comment 1') | 76 | await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoId, 'super comment 1') |
77 | await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, 'super comment 2') | 77 | await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoId, 'super comment 2') |
78 | } | 78 | } |
79 | 79 | ||
80 | await waitJobs(servers) | 80 | await waitJobs(servers) |
@@ -84,18 +84,18 @@ describe('Test syndication feeds', () => { | |||
84 | 84 | ||
85 | it('Should be well formed XML (covers RSS 2.0 and ATOM 1.0 endpoints)', async function () { | 85 | it('Should be well formed XML (covers RSS 2.0 and ATOM 1.0 endpoints)', async function () { |
86 | for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { | 86 | for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { |
87 | const rss = await getXMLfeed(servers[ 0 ].url, feed) | 87 | const rss = await getXMLfeed(servers[0].url, feed) |
88 | expect(rss.text).xml.to.be.valid() | 88 | expect(rss.text).xml.to.be.valid() |
89 | 89 | ||
90 | const atom = await getXMLfeed(servers[ 0 ].url, feed, 'atom') | 90 | const atom = await getXMLfeed(servers[0].url, feed, 'atom') |
91 | expect(atom.text).xml.to.be.valid() | 91 | expect(atom.text).xml.to.be.valid() |
92 | } | 92 | } |
93 | }) | 93 | }) |
94 | 94 | ||
95 | it('Should be well formed JSON (covers JSON feed 1.0 endpoint)', async function () { | 95 | it('Should be well formed JSON (covers JSON feed 1.0 endpoint)', async function () { |
96 | for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { | 96 | for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { |
97 | const json = await getJSONfeed(servers[ 0 ].url, feed) | 97 | const json = await getJSONfeed(servers[0].url, feed) |
98 | expect(JSON.parse(json.text)).to.be.jsonSchema({ 'type': 'object' }) | 98 | expect(JSON.parse(json.text)).to.be.jsonSchema({ type: 'object' }) |
99 | } | 99 | } |
100 | }) | 100 | }) |
101 | }) | 101 | }) |
@@ -118,11 +118,11 @@ describe('Test syndication feeds', () => { | |||
118 | const json = await getJSONfeed(server.url, 'videos') | 118 | const json = await getJSONfeed(server.url, 'videos') |
119 | const jsonObj = JSON.parse(json.text) | 119 | const jsonObj = JSON.parse(json.text) |
120 | expect(jsonObj.items.length).to.be.equal(2) | 120 | expect(jsonObj.items.length).to.be.equal(2) |
121 | expect(jsonObj.items[ 0 ].attachments).to.exist | 121 | expect(jsonObj.items[0].attachments).to.exist |
122 | expect(jsonObj.items[ 0 ].attachments.length).to.be.eq(1) | 122 | expect(jsonObj.items[0].attachments.length).to.be.eq(1) |
123 | expect(jsonObj.items[ 0 ].attachments[ 0 ].mime_type).to.be.eq('application/x-bittorrent') | 123 | expect(jsonObj.items[0].attachments[0].mime_type).to.be.eq('application/x-bittorrent') |
124 | expect(jsonObj.items[ 0 ].attachments[ 0 ].size_in_bytes).to.be.eq(218910) | 124 | expect(jsonObj.items[0].attachments[0].size_in_bytes).to.be.eq(218910) |
125 | expect(jsonObj.items[ 0 ].attachments[ 0 ].url).to.contain('720.torrent') | 125 | expect(jsonObj.items[0].attachments[0].url).to.contain('720.torrent') |
126 | } | 126 | } |
127 | }) | 127 | }) |
128 | 128 | ||
@@ -131,16 +131,16 @@ describe('Test syndication feeds', () => { | |||
131 | const json = await getJSONfeed(servers[0].url, 'videos', { accountId: rootAccountId }) | 131 | const json = await getJSONfeed(servers[0].url, 'videos', { accountId: rootAccountId }) |
132 | const jsonObj = JSON.parse(json.text) | 132 | const jsonObj = JSON.parse(json.text) |
133 | expect(jsonObj.items.length).to.be.equal(1) | 133 | expect(jsonObj.items.length).to.be.equal(1) |
134 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 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') | 135 | expect(jsonObj.items[0].author.name).to.equal('root') |
136 | } | 136 | } |
137 | 137 | ||
138 | { | 138 | { |
139 | const json = await getJSONfeed(servers[0].url, 'videos', { accountId: userAccountId }) | 139 | const json = await getJSONfeed(servers[0].url, 'videos', { accountId: userAccountId }) |
140 | const jsonObj = JSON.parse(json.text) | 140 | const jsonObj = JSON.parse(json.text) |
141 | expect(jsonObj.items.length).to.be.equal(1) | 141 | expect(jsonObj.items.length).to.be.equal(1) |
142 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | 142 | expect(jsonObj.items[0].title).to.equal('user video') |
143 | expect(jsonObj.items[ 0 ].author.name).to.equal('john') | 143 | expect(jsonObj.items[0].author.name).to.equal('john') |
144 | } | 144 | } |
145 | 145 | ||
146 | for (const server of servers) { | 146 | for (const server of servers) { |
@@ -148,14 +148,14 @@ describe('Test syndication feeds', () => { | |||
148 | const json = await getJSONfeed(server.url, 'videos', { accountName: 'root@localhost:' + servers[0].port }) | 148 | const json = await getJSONfeed(server.url, 'videos', { accountName: 'root@localhost:' + servers[0].port }) |
149 | const jsonObj = JSON.parse(json.text) | 149 | const jsonObj = JSON.parse(json.text) |
150 | expect(jsonObj.items.length).to.be.equal(1) | 150 | expect(jsonObj.items.length).to.be.equal(1) |
151 | 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') |
152 | } | 152 | } |
153 | 153 | ||
154 | { | 154 | { |
155 | const json = await getJSONfeed(server.url, 'videos', { accountName: 'john@localhost:' + servers[0].port }) | 155 | const json = await getJSONfeed(server.url, 'videos', { accountName: 'john@localhost:' + servers[0].port }) |
156 | const jsonObj = JSON.parse(json.text) | 156 | const jsonObj = JSON.parse(json.text) |
157 | expect(jsonObj.items.length).to.be.equal(1) | 157 | expect(jsonObj.items.length).to.be.equal(1) |
158 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | 158 | expect(jsonObj.items[0].title).to.equal('user video') |
159 | } | 159 | } |
160 | } | 160 | } |
161 | }) | 161 | }) |
@@ -165,16 +165,16 @@ describe('Test syndication feeds', () => { | |||
165 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: rootChannelId }) | 165 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: rootChannelId }) |
166 | const jsonObj = JSON.parse(json.text) | 166 | const jsonObj = JSON.parse(json.text) |
167 | expect(jsonObj.items.length).to.be.equal(1) | 167 | expect(jsonObj.items.length).to.be.equal(1) |
168 | 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') | 169 | expect(jsonObj.items[0].author.name).to.equal('root') |
170 | } | 170 | } |
171 | 171 | ||
172 | { | 172 | { |
173 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: userChannelId }) | 173 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: userChannelId }) |
174 | const jsonObj = JSON.parse(json.text) | 174 | const jsonObj = JSON.parse(json.text) |
175 | expect(jsonObj.items.length).to.be.equal(1) | 175 | expect(jsonObj.items.length).to.be.equal(1) |
176 | 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') | 177 | expect(jsonObj.items[0].author.name).to.equal('john') |
178 | } | 178 | } |
179 | 179 | ||
180 | for (const server of servers) { | 180 | for (const server of servers) { |
@@ -182,14 +182,14 @@ describe('Test syndication feeds', () => { | |||
182 | const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'root_channel@localhost:' + servers[0].port }) | 182 | const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'root_channel@localhost:' + servers[0].port }) |
183 | const jsonObj = JSON.parse(json.text) | 183 | const jsonObj = JSON.parse(json.text) |
184 | expect(jsonObj.items.length).to.be.equal(1) | 184 | expect(jsonObj.items.length).to.be.equal(1) |
185 | 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') |
186 | } | 186 | } |
187 | 187 | ||
188 | { | 188 | { |
189 | const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'john_channel@localhost:' + servers[0].port }) | 189 | const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'john_channel@localhost:' + servers[0].port }) |
190 | const jsonObj = JSON.parse(json.text) | 190 | const jsonObj = JSON.parse(json.text) |
191 | expect(jsonObj.items.length).to.be.equal(1) | 191 | expect(jsonObj.items.length).to.be.equal(1) |
192 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | 192 | expect(jsonObj.items[0].title).to.equal('user video') |
193 | } | 193 | } |
194 | } | 194 | } |
195 | }) | 195 | }) |
@@ -202,8 +202,8 @@ describe('Test syndication feeds', () => { | |||
202 | 202 | ||
203 | const jsonObj = JSON.parse(json.text) | 203 | const jsonObj = JSON.parse(json.text) |
204 | expect(jsonObj.items.length).to.be.equal(2) | 204 | expect(jsonObj.items.length).to.be.equal(2) |
205 | expect(jsonObj.items[ 0 ].html_content).to.equal('super comment 2') | 205 | expect(jsonObj.items[0].html_content).to.equal('super comment 2') |
206 | expect(jsonObj.items[ 1 ].html_content).to.equal('super comment 1') | 206 | expect(jsonObj.items[1].html_content).to.equal('super comment 1') |
207 | } | 207 | } |
208 | }) | 208 | }) |
209 | }) | 209 | }) |
diff --git a/server/tests/helpers/comment-model.ts b/server/tests/helpers/comment-model.ts index ebfd779e1..4c51b7000 100644 --- a/server/tests/helpers/comment-model.ts +++ b/server/tests/helpers/comment-model.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -20,7 +20,7 @@ describe('Comment model', function () { | |||
20 | 20 | ||
21 | comment.text = '@florian @jean@localhost:9000 @flo @another@localhost:9000 @flo2@jean.com hello ' + | 21 | comment.text = '@florian @jean@localhost:9000 @flo @another@localhost:9000 @flo2@jean.com hello ' + |
22 | 'email@localhost:9000 coucou.com no? @chocobozzz @chocobozzz @end' | 22 | 'email@localhost:9000 coucou.com no? @chocobozzz @chocobozzz @end' |
23 | const result = comment.extractMentions().sort() | 23 | const result = comment.extractMentions().sort((a, b) => a.localeCompare(b)) |
24 | 24 | ||
25 | expect(result).to.deep.equal([ 'another', 'chocobozzz', 'end', 'flo', 'florian', 'jean' ]) | 25 | expect(result).to.deep.equal([ 'another', 'chocobozzz', 'end', 'flo', 'florian', 'jean' ]) |
26 | }) | 26 | }) |
diff --git a/server/tests/helpers/core-utils.ts b/server/tests/helpers/core-utils.ts index 31fc6dd7c..c028b316d 100644 --- a/server/tests/helpers/core-utils.ts +++ b/server/tests/helpers/core-utils.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/helpers/request.ts b/server/tests/helpers/request.ts index a754bc6e2..f8b2d599b 100644 --- a/server/tests/helpers/request.ts +++ b/server/tests/helpers/request.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' | 4 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' |
diff --git a/server/tests/misc-endpoints.ts b/server/tests/misc-endpoints.ts index ab2dd3a0f..32b035c9e 100644 --- a/server/tests/misc-endpoints.ts +++ b/server/tests/misc-endpoints.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
diff --git a/server/tests/plugins/action-hooks.ts b/server/tests/plugins/action-hooks.ts index 510ec3151..ca57a4b51 100644 --- a/server/tests/plugins/action-hooks.ts +++ b/server/tests/plugins/action-hooks.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | ||
4 | import 'mocha' | 3 | import 'mocha' |
5 | import { | 4 | import { |
6 | cleanupTests, | 5 | cleanupTests, |
@@ -17,18 +16,18 @@ import { | |||
17 | createUser, | 16 | createUser, |
18 | deleteVideoComment, | 17 | deleteVideoComment, |
19 | getPluginTestPath, | 18 | getPluginTestPath, |
20 | installPlugin, login, | 19 | installPlugin, |
21 | registerUser, removeUser, | 20 | registerUser, |
21 | removeUser, | ||
22 | setAccessTokensToServers, | 22 | setAccessTokensToServers, |
23 | unblockUser, updateUser, | 23 | unblockUser, |
24 | updateUser, | ||
24 | updateVideo, | 25 | updateVideo, |
25 | uploadVideo, | 26 | uploadVideo, |
26 | viewVideo, | 27 | userLogin, |
27 | userLogin | 28 | viewVideo |
28 | } from '../../../shared/extra-utils' | 29 | } from '../../../shared/extra-utils' |
29 | 30 | ||
30 | const expect = chai.expect | ||
31 | |||
32 | describe('Test plugin action hooks', function () { | 31 | describe('Test plugin action hooks', function () { |
33 | let servers: ServerInfo[] | 32 | let servers: ServerInfo[] |
34 | let videoUUID: string | 33 | let videoUUID: string |
diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts index 6a5ea4641..6c1fd40ba 100644 --- a/server/tests/plugins/filter-hooks.ts +++ b/server/tests/plugins/filter-hooks.ts | |||
@@ -1,34 +1,27 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { cleanupTests, flushAndRunMultipleServers, ServerInfo } from '../../../shared/extra-utils/server/servers' |
6 | cleanupTests, | ||
7 | flushAndRunMultipleServers, | ||
8 | flushAndRunServer, killallServers, reRunServer, | ||
9 | ServerInfo, | ||
10 | waitUntilLog | ||
11 | } from '../../../shared/extra-utils/server/servers' | ||
12 | import { | 6 | import { |
13 | addVideoCommentReply, | 7 | addVideoCommentReply, |
14 | addVideoCommentThread, | 8 | addVideoCommentThread, |
15 | deleteVideoComment, | 9 | doubleFollow, |
10 | getConfig, | ||
16 | getPluginTestPath, | 11 | getPluginTestPath, |
17 | getVideosList, | ||
18 | installPlugin, | ||
19 | removeVideo, | ||
20 | setAccessTokensToServers, | ||
21 | updateVideo, | ||
22 | uploadVideo, | ||
23 | viewVideo, | ||
24 | getVideosListPagination, | ||
25 | getVideo, | 12 | getVideo, |
26 | getVideoCommentThreads, | 13 | getVideoCommentThreads, |
14 | getVideosList, | ||
15 | getVideosListPagination, | ||
27 | getVideoThreadComments, | 16 | getVideoThreadComments, |
28 | getVideoWithToken, | 17 | getVideoWithToken, |
18 | installPlugin, | ||
19 | registerUser, | ||
20 | setAccessTokensToServers, | ||
29 | setDefaultVideoChannel, | 21 | setDefaultVideoChannel, |
30 | waitJobs, | 22 | updateVideo, |
31 | doubleFollow, getConfig, registerUser | 23 | uploadVideo, |
24 | waitJobs | ||
32 | } from '../../../shared/extra-utils' | 25 | } from '../../../shared/extra-utils' |
33 | import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' | 26 | import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' |
34 | import { VideoDetails } from '../../../shared/models/videos' | 27 | import { VideoDetails } from '../../../shared/models/videos' |
@@ -140,7 +133,7 @@ describe('Test plugin filter hooks', function () { | |||
140 | } | 133 | } |
141 | 134 | ||
142 | it('Should blacklist on upload', async function () { | 135 | it('Should blacklist on upload', async function () { |
143 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video please blacklist me' }) | 136 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video please blacklist me' }) |
144 | await checkIsBlacklisted(res, true) | 137 | await checkIsBlacklisted(res, true) |
145 | }) | 138 | }) |
146 | 139 | ||
@@ -157,18 +150,18 @@ describe('Test plugin filter hooks', function () { | |||
157 | }) | 150 | }) |
158 | 151 | ||
159 | it('Should blacklist on update', async function () { | 152 | it('Should blacklist on update', async function () { |
160 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video' }) | 153 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' }) |
161 | const videoId = res.body.video.uuid | 154 | const videoId = res.body.video.uuid |
162 | await checkIsBlacklisted(res, false) | 155 | await checkIsBlacklisted(res, false) |
163 | 156 | ||
164 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, { name: 'please blacklist me' }) | 157 | await updateVideo(servers[0].url, servers[0].accessToken, videoId, { name: 'please blacklist me' }) |
165 | await checkIsBlacklisted(res, true) | 158 | await checkIsBlacklisted(res, true) |
166 | }) | 159 | }) |
167 | 160 | ||
168 | it('Should blacklist on remote upload', async function () { | 161 | it('Should blacklist on remote upload', async function () { |
169 | this.timeout(45000) | 162 | this.timeout(45000) |
170 | 163 | ||
171 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'remote please blacklist me' }) | 164 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'remote please blacklist me' }) |
172 | await waitJobs(servers) | 165 | await waitJobs(servers) |
173 | 166 | ||
174 | await checkIsBlacklisted(res, true) | 167 | await checkIsBlacklisted(res, true) |
@@ -177,7 +170,7 @@ describe('Test plugin filter hooks', function () { | |||
177 | it('Should blacklist on remote update', async function () { | 170 | it('Should blacklist on remote update', async function () { |
178 | this.timeout(45000) | 171 | this.timeout(45000) |
179 | 172 | ||
180 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video' }) | 173 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video' }) |
181 | await waitJobs(servers) | 174 | await waitJobs(servers) |
182 | 175 | ||
183 | const videoId = res.body.video.uuid | 176 | const videoId = res.body.video.uuid |
diff --git a/server/tests/plugins/translations.ts b/server/tests/plugins/translations.ts index 88d91a033..8dc2043b8 100644 --- a/server/tests/plugins/translations.ts +++ b/server/tests/plugins/translations.ts | |||
@@ -1,38 +1,15 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../shared/extra-utils/server/servers' | ||
5 | import { | 6 | import { |
6 | cleanupTests, | ||
7 | flushAndRunMultipleServers, | ||
8 | flushAndRunServer, killallServers, reRunServer, | ||
9 | ServerInfo, | ||
10 | waitUntilLog | ||
11 | } from '../../../shared/extra-utils/server/servers' | ||
12 | import { | ||
13 | addVideoCommentReply, | ||
14 | addVideoCommentThread, | ||
15 | deleteVideoComment, | ||
16 | getPluginTestPath, | 7 | getPluginTestPath, |
17 | getVideosList, | 8 | getPluginTranslations, |
18 | installPlugin, | 9 | installPlugin, |
19 | removeVideo, | ||
20 | setAccessTokensToServers, | 10 | setAccessTokensToServers, |
21 | updateVideo, | 11 | uninstallPlugin |
22 | uploadVideo, | ||
23 | viewVideo, | ||
24 | getVideosListPagination, | ||
25 | getVideo, | ||
26 | getVideoCommentThreads, | ||
27 | getVideoThreadComments, | ||
28 | getVideoWithToken, | ||
29 | setDefaultVideoChannel, | ||
30 | waitJobs, | ||
31 | doubleFollow, getVideoLanguages, getVideoLicences, getVideoCategories, uninstallPlugin, getPluginTranslations | ||
32 | } from '../../../shared/extra-utils' | 12 | } from '../../../shared/extra-utils' |
33 | import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' | ||
34 | import { VideoDetails } from '../../../shared/models/videos' | ||
35 | import { getYoutubeVideoUrl, importVideo } from '../../../shared/extra-utils/videos/video-imports' | ||
36 | 13 | ||
37 | const expect = chai.expect | 14 | const expect = chai.expect |
38 | 15 | ||
@@ -69,7 +46,7 @@ describe('Test plugin translations', function () { | |||
69 | 46 | ||
70 | expect(res.body).to.deep.equal({ | 47 | expect(res.body).to.deep.equal({ |
71 | 'peertube-plugin-test': { | 48 | 'peertube-plugin-test': { |
72 | 'Hi': 'Coucou' | 49 | Hi: 'Coucou' |
73 | }, | 50 | }, |
74 | 'peertube-plugin-test-two': { | 51 | 'peertube-plugin-test-two': { |
75 | 'Hello world': 'Bonjour le monde' | 52 | 'Hello world': 'Bonjour le monde' |
@@ -95,7 +72,7 @@ describe('Test plugin translations', function () { | |||
95 | 72 | ||
96 | expect(res.body).to.deep.equal({ | 73 | expect(res.body).to.deep.equal({ |
97 | 'peertube-plugin-test': { | 74 | 'peertube-plugin-test': { |
98 | 'Hi': 'Coucou' | 75 | Hi: 'Coucou' |
99 | } | 76 | } |
100 | }) | 77 | }) |
101 | } | 78 | } |
diff --git a/server/tests/plugins/video-constants.ts b/server/tests/plugins/video-constants.ts index 6562e2b45..5374b5ecc 100644 --- a/server/tests/plugins/video-constants.ts +++ b/server/tests/plugins/video-constants.ts | |||
@@ -1,38 +1,20 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../shared/extra-utils/server/servers' | ||
5 | import { | 6 | import { |
6 | cleanupTests, | ||
7 | flushAndRunMultipleServers, | ||
8 | flushAndRunServer, killallServers, reRunServer, | ||
9 | ServerInfo, | ||
10 | waitUntilLog | ||
11 | } from '../../../shared/extra-utils/server/servers' | ||
12 | import { | ||
13 | addVideoCommentReply, | ||
14 | addVideoCommentThread, | ||
15 | deleteVideoComment, | ||
16 | getPluginTestPath, | 7 | getPluginTestPath, |
17 | getVideosList, | 8 | getVideo, |
9 | getVideoCategories, | ||
10 | getVideoLanguages, | ||
11 | getVideoLicences, | ||
18 | installPlugin, | 12 | installPlugin, |
19 | removeVideo, | ||
20 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
21 | updateVideo, | 14 | uninstallPlugin, |
22 | uploadVideo, | 15 | uploadVideo |
23 | viewVideo, | ||
24 | getVideosListPagination, | ||
25 | getVideo, | ||
26 | getVideoCommentThreads, | ||
27 | getVideoThreadComments, | ||
28 | getVideoWithToken, | ||
29 | setDefaultVideoChannel, | ||
30 | waitJobs, | ||
31 | doubleFollow, getVideoLanguages, getVideoLicences, getVideoCategories, uninstallPlugin | ||
32 | } from '../../../shared/extra-utils' | 16 | } from '../../../shared/extra-utils' |
33 | import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' | ||
34 | import { VideoDetails } from '../../../shared/models/videos' | 17 | import { VideoDetails } from '../../../shared/models/videos' |
35 | import { getYoutubeVideoUrl, importVideo } from '../../../shared/extra-utils/videos/video-imports' | ||
36 | 18 | ||
37 | const expect = chai.expect | 19 | const expect = chai.expect |
38 | 20 | ||
@@ -104,33 +86,33 @@ describe('Test plugin altering video constants', function () { | |||
104 | const res = await getVideoLanguages(server.url) | 86 | const res = await getVideoLanguages(server.url) |
105 | const languages = res.body | 87 | const languages = res.body |
106 | 88 | ||
107 | expect(languages[ 'en' ]).to.equal('English') | 89 | expect(languages['en']).to.equal('English') |
108 | expect(languages[ 'fr' ]).to.equal('French') | 90 | expect(languages['fr']).to.equal('French') |
109 | 91 | ||
110 | expect(languages[ 'al_bhed' ]).to.not.exist | 92 | expect(languages['al_bhed']).to.not.exist |
111 | expect(languages[ 'al_bhed2' ]).to.not.exist | 93 | expect(languages['al_bhed2']).to.not.exist |
112 | } | 94 | } |
113 | 95 | ||
114 | { | 96 | { |
115 | const res = await getVideoCategories(server.url) | 97 | const res = await getVideoCategories(server.url) |
116 | const categories = res.body | 98 | const categories = res.body |
117 | 99 | ||
118 | expect(categories[ 1 ]).to.equal('Music') | 100 | expect(categories[1]).to.equal('Music') |
119 | expect(categories[ 2 ]).to.equal('Films') | 101 | expect(categories[2]).to.equal('Films') |
120 | 102 | ||
121 | expect(categories[ 42 ]).to.not.exist | 103 | expect(categories[42]).to.not.exist |
122 | expect(categories[ 43 ]).to.not.exist | 104 | expect(categories[43]).to.not.exist |
123 | } | 105 | } |
124 | 106 | ||
125 | { | 107 | { |
126 | const res = await getVideoLicences(server.url) | 108 | const res = await getVideoLicences(server.url) |
127 | const licences = res.body | 109 | const licences = res.body |
128 | 110 | ||
129 | expect(licences[ 1 ]).to.equal('Attribution') | 111 | expect(licences[1]).to.equal('Attribution') |
130 | expect(licences[ 7 ]).to.equal('Public Domain Dedication') | 112 | expect(licences[7]).to.equal('Public Domain Dedication') |
131 | 113 | ||
132 | expect(licences[ 42 ]).to.not.exist | 114 | expect(licences[42]).to.not.exist |
133 | expect(licences[ 43 ]).to.not.exist | 115 | expect(licences[43]).to.not.exist |
134 | } | 116 | } |
135 | }) | 117 | }) |
136 | 118 | ||
diff --git a/server/tests/real-world/populate-database.ts b/server/tests/real-world/populate-database.ts deleted file mode 100644 index b1c1688e7..000000000 --- a/server/tests/real-world/populate-database.ts +++ /dev/null | |||
@@ -1,122 +0,0 @@ | |||
1 | import { VideoRateType } from '../../../shared' | ||
2 | import { | ||
3 | addVideoChannel, | ||
4 | createUser, | ||
5 | flushTests, | ||
6 | getVideosList, | ||
7 | killallServers, | ||
8 | rateVideo, | ||
9 | flushAndRunServer, | ||
10 | ServerInfo, | ||
11 | setAccessTokensToServers, | ||
12 | uploadVideo | ||
13 | } from '../../../shared/extra-utils' | ||
14 | import * as Bluebird from 'bluebird' | ||
15 | |||
16 | start() | ||
17 | .catch(err => console.error(err)) | ||
18 | |||
19 | // ---------------------------------------------------------------------------- | ||
20 | |||
21 | async function start () { | ||
22 | |||
23 | console.log('Flushed tests.') | ||
24 | |||
25 | const server = await flushAndRunServer(6) | ||
26 | |||
27 | process.on('exit', async () => { | ||
28 | killallServers([ server ]) | ||
29 | return | ||
30 | }) | ||
31 | process.on('SIGINT', goodbye) | ||
32 | process.on('SIGTERM', goodbye) | ||
33 | |||
34 | await setAccessTokensToServers([ server ]) | ||
35 | |||
36 | console.log('Servers ran.') | ||
37 | |||
38 | // Forever | ||
39 | const fakeTab = Array.from(Array(1000000).keys()) | ||
40 | const funs = [ | ||
41 | uploadCustom | ||
42 | // uploadCustom, | ||
43 | // uploadCustom, | ||
44 | // uploadCustom, | ||
45 | // likeCustom, | ||
46 | // createUserCustom, | ||
47 | // createCustomChannel | ||
48 | ] | ||
49 | const promises = [] | ||
50 | |||
51 | for (const fun of funs) { | ||
52 | promises.push( | ||
53 | Bluebird.map(fakeTab, () => { | ||
54 | return fun(server).catch(err => console.error(err)) | ||
55 | }, { concurrency: 3 }) | ||
56 | ) | ||
57 | } | ||
58 | |||
59 | await Promise.all(promises) | ||
60 | } | ||
61 | |||
62 | function getRandomInt (min, max) { | ||
63 | return Math.floor(Math.random() * (max - min)) + min | ||
64 | } | ||
65 | |||
66 | function createCustomChannel (server: ServerInfo) { | ||
67 | const videoChannel = { | ||
68 | name: Date.now().toString(), | ||
69 | displayName: Date.now().toString(), | ||
70 | description: Date.now().toString() | ||
71 | } | ||
72 | |||
73 | return addVideoChannel(server.url, server.accessToken, videoChannel) | ||
74 | } | ||
75 | |||
76 | function createUserCustom (server: ServerInfo) { | ||
77 | const username = Date.now().toString() + getRandomInt(0, 100000) | ||
78 | console.log('Creating user %s.', username) | ||
79 | |||
80 | return createUser({ url: server.url, accessToken: server.accessToken, username: username, password: 'coucou' }) | ||
81 | } | ||
82 | |||
83 | function uploadCustom (server: ServerInfo) { | ||
84 | console.log('Uploading video.') | ||
85 | |||
86 | const videoAttributes = { | ||
87 | name: Date.now() + ' name', | ||
88 | category: 4, | ||
89 | nsfw: false, | ||
90 | licence: 2, | ||
91 | language: 'en', | ||
92 | description: Date.now() + ' description', | ||
93 | tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ], | ||
94 | fixture: 'video_short.mp4' | ||
95 | } | ||
96 | |||
97 | return uploadVideo(server.url, server.accessToken, videoAttributes) | ||
98 | } | ||
99 | |||
100 | function likeCustom (server: ServerInfo) { | ||
101 | return rateCustom(server, 'like') | ||
102 | } | ||
103 | |||
104 | function dislikeCustom (server: ServerInfo) { | ||
105 | return rateCustom(server, 'dislike') | ||
106 | } | ||
107 | |||
108 | async function rateCustom (server: ServerInfo, rating: VideoRateType) { | ||
109 | const res = await getVideosList(server.url) | ||
110 | |||
111 | const videos = res.body.data | ||
112 | if (videos.length === 0) return undefined | ||
113 | |||
114 | const videoToRate = videos[getRandomInt(0, videos.length)] | ||
115 | |||
116 | console.log('Rating (%s) video.', rating) | ||
117 | return rateVideo(server.url, server.accessToken, videoToRate.id, rating) | ||
118 | } | ||
119 | |||
120 | function goodbye () { | ||
121 | return process.exit(-1) | ||
122 | } | ||
diff --git a/server/tests/real-world/real-world.ts b/server/tests/real-world/real-world.ts deleted file mode 100644 index cba5ac311..000000000 --- a/server/tests/real-world/real-world.ts +++ /dev/null | |||
@@ -1,375 +0,0 @@ | |||
1 | // /!\ Before imports /!\ | ||
2 | process.env.NODE_ENV = 'test' | ||
3 | |||
4 | import * as program from 'commander' | ||
5 | import { Video, VideoFile, VideoRateType } from '../../../shared' | ||
6 | import { JobState } from '../../../shared/models' | ||
7 | import { | ||
8 | flushAndRunMultipleServers, | ||
9 | flushTests, follow, | ||
10 | getVideo, | ||
11 | getVideosList, getVideosListPagination, | ||
12 | killallServers, | ||
13 | removeVideo, | ||
14 | ServerInfo as DefaultServerInfo, | ||
15 | setAccessTokensToServers, | ||
16 | updateVideo, | ||
17 | uploadVideo, viewVideo, | ||
18 | wait | ||
19 | } from '../../../shared/extra-utils' | ||
20 | import { getJobsListPaginationAndSort } from '../../../shared/extra-utils/server/jobs' | ||
21 | |||
22 | interface ServerInfo extends DefaultServerInfo { | ||
23 | requestsNumber: number | ||
24 | } | ||
25 | |||
26 | program | ||
27 | .option('-c, --create [weight]', 'Weight for creating videos') | ||
28 | .option('-r, --remove [weight]', 'Weight for removing videos') | ||
29 | .option('-u, --update [weight]', 'Weight for updating videos') | ||
30 | .option('-v, --view [weight]', 'Weight for viewing videos') | ||
31 | .option('-l, --like [weight]', 'Weight for liking videos') | ||
32 | .option('-s, --dislike [weight]', 'Weight for disliking videos') | ||
33 | .option('-p, --servers [n]', 'Number of servers to run (3 or 6)', /^3|6$/, 3) | ||
34 | .option('-i, --interval-action [interval]', 'Interval in ms for an action') | ||
35 | .option('-I, --interval-integrity [interval]', 'Interval in ms for an integrity check') | ||
36 | .option('-f, --flush', 'Flush data on exit') | ||
37 | .option('-d, --difference', 'Display difference if integrity is not okay') | ||
38 | .parse(process.argv) | ||
39 | |||
40 | const createWeight = program['create'] !== undefined ? parseInt(program['create'], 10) : 5 | ||
41 | const removeWeight = program['remove'] !== undefined ? parseInt(program['remove'], 10) : 4 | ||
42 | const updateWeight = program['update'] !== undefined ? parseInt(program['update'], 10) : 4 | ||
43 | const viewWeight = program['view'] !== undefined ? parseInt(program['view'], 10) : 4 | ||
44 | const likeWeight = program['like'] !== undefined ? parseInt(program['like'], 10) : 4 | ||
45 | const dislikeWeight = program['dislike'] !== undefined ? parseInt(program['dislike'], 10) : 4 | ||
46 | const flushAtExit = program['flush'] || false | ||
47 | const actionInterval = program['intervalAction'] !== undefined ? parseInt(program['intervalAction'], 10) : 500 | ||
48 | const integrityInterval = program['intervalIntegrity'] !== undefined ? parseInt(program['intervalIntegrity'], 10) : 60000 | ||
49 | const displayDiffOnFail = program['difference'] || false | ||
50 | |||
51 | const numberOfServers = 6 | ||
52 | |||
53 | console.log( | ||
54 | 'Create weight: %d, update weight: %d, remove weight: %d, view weight: %d, like weight: %d, dislike weight: %d.', | ||
55 | createWeight, updateWeight, removeWeight, viewWeight, likeWeight, dislikeWeight | ||
56 | ) | ||
57 | |||
58 | if (flushAtExit) { | ||
59 | console.log('Program will flush data on exit.') | ||
60 | } else { | ||
61 | console.log('Program will not flush data on exit.') | ||
62 | } | ||
63 | if (displayDiffOnFail) { | ||
64 | console.log('Program will display diff on failure.') | ||
65 | } else { | ||
66 | console.log('Program will not display diff on failure') | ||
67 | } | ||
68 | console.log('Interval in ms for each action: %d.', actionInterval) | ||
69 | console.log('Interval in ms for each integrity check: %d.', integrityInterval) | ||
70 | |||
71 | console.log('Run servers...') | ||
72 | |||
73 | start() | ||
74 | |||
75 | // ---------------------------------------------------------------------------- | ||
76 | |||
77 | async function start () { | ||
78 | const servers = await runServers(numberOfServers) | ||
79 | |||
80 | process.on('exit', async () => { | ||
81 | await exitServers(servers, flushAtExit) | ||
82 | |||
83 | return | ||
84 | }) | ||
85 | process.on('SIGINT', goodbye) | ||
86 | process.on('SIGTERM', goodbye) | ||
87 | |||
88 | console.log('Servers ran') | ||
89 | initializeRequestsPerServer(servers) | ||
90 | |||
91 | let checking = false | ||
92 | |||
93 | setInterval(async () => { | ||
94 | if (checking === true) return | ||
95 | |||
96 | const rand = getRandomInt(0, createWeight + updateWeight + removeWeight + viewWeight + likeWeight + dislikeWeight) | ||
97 | |||
98 | const numServer = getRandomNumServer(servers) | ||
99 | servers[numServer].requestsNumber++ | ||
100 | |||
101 | if (rand < createWeight) { | ||
102 | await upload(servers, numServer) | ||
103 | } else if (rand < createWeight + updateWeight) { | ||
104 | await update(servers, numServer) | ||
105 | } else if (rand < createWeight + updateWeight + removeWeight) { | ||
106 | await remove(servers, numServer) | ||
107 | } else if (rand < createWeight + updateWeight + removeWeight + viewWeight) { | ||
108 | await view(servers, numServer) | ||
109 | } else if (rand < createWeight + updateWeight + removeWeight + viewWeight + likeWeight) { | ||
110 | await like(servers, numServer) | ||
111 | } else { | ||
112 | await dislike(servers, numServer) | ||
113 | } | ||
114 | }, actionInterval) | ||
115 | |||
116 | // The function will check the consistency between servers (should have the same videos with same attributes...) | ||
117 | setInterval(function () { | ||
118 | if (checking === true) return | ||
119 | |||
120 | console.log('Checking integrity...') | ||
121 | checking = true | ||
122 | |||
123 | const waitingInterval = setInterval(async () => { | ||
124 | const pendingRequests = await isTherePendingRequests(servers) | ||
125 | if (pendingRequests === true) { | ||
126 | console.log('A server has pending requests, waiting...') | ||
127 | return | ||
128 | } | ||
129 | |||
130 | // Even if there are no pending request, wait some potential processes | ||
131 | await wait(2000) | ||
132 | await checkIntegrity(servers) | ||
133 | |||
134 | initializeRequestsPerServer(servers) | ||
135 | checking = false | ||
136 | clearInterval(waitingInterval) | ||
137 | }, 10000) | ||
138 | }, integrityInterval) | ||
139 | } | ||
140 | |||
141 | function initializeRequestsPerServer (servers: ServerInfo[]) { | ||
142 | servers.forEach(server => server.requestsNumber = 0) | ||
143 | } | ||
144 | |||
145 | function getRandomInt (min, max) { | ||
146 | return Math.floor(Math.random() * (max - min)) + min | ||
147 | } | ||
148 | |||
149 | function getRandomNumServer (servers) { | ||
150 | return getRandomInt(0, servers.length) | ||
151 | } | ||
152 | |||
153 | async function runServers (numberOfServers: number) { | ||
154 | const servers: ServerInfo[] = (await flushAndRunMultipleServers(numberOfServers)) | ||
155 | .map(s => Object.assign({ requestsNumber: 0 }, s)) | ||
156 | |||
157 | // Get the access tokens | ||
158 | await setAccessTokensToServers(servers) | ||
159 | |||
160 | for (let i = 0; i < numberOfServers; i++) { | ||
161 | for (let j = 0; j < numberOfServers; j++) { | ||
162 | if (i === j) continue | ||
163 | |||
164 | await follow(servers[i].url, [ servers[j].url ], servers[i].accessToken) | ||
165 | } | ||
166 | } | ||
167 | |||
168 | return servers | ||
169 | } | ||
170 | |||
171 | async function exitServers (servers: ServerInfo[], flushAtExit: boolean) { | ||
172 | killallServers(servers) | ||
173 | |||
174 | if (flushAtExit) await flushTests() | ||
175 | } | ||
176 | |||
177 | function upload (servers: ServerInfo[], numServer: number) { | ||
178 | console.log('Uploading video to server ' + numServer) | ||
179 | |||
180 | const videoAttributes = { | ||
181 | name: Date.now() + ' name', | ||
182 | category: 4, | ||
183 | nsfw: false, | ||
184 | licence: 2, | ||
185 | language: 'en', | ||
186 | description: Date.now() + ' description', | ||
187 | tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ], | ||
188 | fixture: 'video_short1.webm' | ||
189 | } | ||
190 | return uploadVideo(servers[numServer].url, servers[numServer].accessToken, videoAttributes) | ||
191 | } | ||
192 | |||
193 | async function update (servers: ServerInfo[], numServer: number) { | ||
194 | const res = await getVideosList(servers[numServer].url) | ||
195 | |||
196 | const videos = res.body.data.filter(video => video.isLocal === true) | ||
197 | if (videos.length === 0) return undefined | ||
198 | |||
199 | const toUpdate = videos[getRandomInt(0, videos.length)].id | ||
200 | const attributes = { | ||
201 | name: Date.now() + ' name', | ||
202 | description: Date.now() + ' description', | ||
203 | tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ] | ||
204 | } | ||
205 | |||
206 | console.log('Updating video of server ' + numServer) | ||
207 | |||
208 | return updateVideo(servers[numServer].url, servers[numServer].accessToken, toUpdate, attributes) | ||
209 | } | ||
210 | |||
211 | async function remove (servers: ServerInfo[], numServer: number) { | ||
212 | const res = await getVideosList(servers[numServer].url) | ||
213 | const videos = res.body.data.filter(video => video.isLocal === true) | ||
214 | if (videos.length === 0) return undefined | ||
215 | |||
216 | const toRemove = videos[getRandomInt(0, videos.length)].id | ||
217 | |||
218 | console.log('Removing video from server ' + numServer) | ||
219 | return removeVideo(servers[numServer].url, servers[numServer].accessToken, toRemove) | ||
220 | } | ||
221 | |||
222 | async function view (servers: ServerInfo[], numServer: number) { | ||
223 | const res = await getVideosList(servers[numServer].url) | ||
224 | |||
225 | const videos = res.body.data | ||
226 | if (videos.length === 0) return undefined | ||
227 | |||
228 | const toView = videos[getRandomInt(0, videos.length)].id | ||
229 | |||
230 | console.log('Viewing video from server ' + numServer) | ||
231 | return viewVideo(servers[numServer].url, toView) | ||
232 | } | ||
233 | |||
234 | function like (servers: ServerInfo[], numServer: number) { | ||
235 | return rate(servers, numServer, 'like') | ||
236 | } | ||
237 | |||
238 | function dislike (servers: ServerInfo[], numServer: number) { | ||
239 | return rate(servers, numServer, 'dislike') | ||
240 | } | ||
241 | |||
242 | async function rate (servers: ServerInfo[], numServer: number, rating: VideoRateType) { | ||
243 | const res = await getVideosList(servers[numServer].url) | ||
244 | |||
245 | const videos = res.body.data | ||
246 | if (videos.length === 0) return undefined | ||
247 | |||
248 | const toRate = videos[getRandomInt(0, videos.length)].id | ||
249 | |||
250 | console.log('Rating (%s) video from server %d', rating, numServer) | ||
251 | return getVideo(servers[numServer].url, toRate) | ||
252 | } | ||
253 | |||
254 | async function checkIntegrity (servers: ServerInfo[]) { | ||
255 | const videos: Video[][] = [] | ||
256 | const tasks: Promise<any>[] = [] | ||
257 | |||
258 | // Fetch all videos and remove some fields that can differ between servers | ||
259 | for (const server of servers) { | ||
260 | const p = getVideosListPagination(server.url, 0, 1000000, '-createdAt') | ||
261 | .then(res => videos.push(res.body.data)) | ||
262 | tasks.push(p) | ||
263 | } | ||
264 | |||
265 | await Promise.all(tasks) | ||
266 | |||
267 | let i = 0 | ||
268 | for (const video of videos) { | ||
269 | const differences = areDifferences(video, videos[0]) | ||
270 | if (differences !== undefined) { | ||
271 | console.error('Integrity not ok with server %d!', i + 1) | ||
272 | |||
273 | if (displayDiffOnFail) { | ||
274 | console.log(differences) | ||
275 | } | ||
276 | |||
277 | process.exit(-1) | ||
278 | } | ||
279 | |||
280 | i++ | ||
281 | } | ||
282 | |||
283 | console.log('Integrity ok.') | ||
284 | } | ||
285 | |||
286 | function areDifferences (videos1: Video[], videos2: Video[]) { | ||
287 | // Remove some keys we don't want to compare | ||
288 | videos1.concat(videos2).forEach(video => { | ||
289 | delete video.id | ||
290 | delete video.isLocal | ||
291 | delete video.thumbnailPath | ||
292 | delete video.updatedAt | ||
293 | delete video.views | ||
294 | }) | ||
295 | |||
296 | if (videos1.length !== videos2.length) { | ||
297 | return `Videos length are different (${videos1.length}/${videos2.length}).` | ||
298 | } | ||
299 | |||
300 | for (const video1 of videos1) { | ||
301 | const video2 = videos2.find(video => video.uuid === video1.uuid) | ||
302 | |||
303 | if (!video2) return 'Video ' + video1.uuid + ' is missing.' | ||
304 | |||
305 | for (const videoKey of Object.keys(video1)) { | ||
306 | const attribute1 = video1[videoKey] | ||
307 | const attribute2 = video2[videoKey] | ||
308 | |||
309 | if (videoKey === 'tags') { | ||
310 | if (attribute1.length !== attribute2.length) { | ||
311 | return 'Tags are different.' | ||
312 | } | ||
313 | |||
314 | attribute1.forEach(tag1 => { | ||
315 | if (attribute2.indexOf(tag1) === -1) { | ||
316 | return 'Tag ' + tag1 + ' is missing.' | ||
317 | } | ||
318 | }) | ||
319 | } else if (videoKey === 'files') { | ||
320 | if (attribute1.length !== attribute2.length) { | ||
321 | return 'Video files are different.' | ||
322 | } | ||
323 | |||
324 | attribute1.forEach((videoFile1: VideoFile) => { | ||
325 | const videoFile2: VideoFile = attribute2.find(videoFile => videoFile.magnetUri === videoFile1.magnetUri) | ||
326 | if (!videoFile2) { | ||
327 | return `Video ${video1.uuid} has missing video file ${videoFile1.magnetUri}.` | ||
328 | } | ||
329 | |||
330 | if (videoFile1.size !== videoFile2.size || videoFile1.resolution.label !== videoFile2.resolution.label) { | ||
331 | return `Video ${video1.uuid} has different video file ${videoFile1.magnetUri}.` | ||
332 | } | ||
333 | }) | ||
334 | } else { | ||
335 | if (attribute1 !== attribute2) { | ||
336 | return `Video ${video1.uuid} has different value for attribute ${videoKey}.` | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | |||
342 | return undefined | ||
343 | } | ||
344 | |||
345 | function goodbye () { | ||
346 | return process.exit(-1) | ||
347 | } | ||
348 | |||
349 | async function isTherePendingRequests (servers: ServerInfo[]) { | ||
350 | const states: JobState[] = [ 'waiting', 'active', 'delayed' ] | ||
351 | const tasks: Promise<any>[] = [] | ||
352 | let pendingRequests = false | ||
353 | |||
354 | // Check if each server has pending request | ||
355 | for (const server of servers) { | ||
356 | for (const state of states) { | ||
357 | const p = getJobsListPaginationAndSort({ | ||
358 | url: server.url, | ||
359 | accessToken: server.accessToken, | ||
360 | state: state, | ||
361 | start: 0, | ||
362 | count: 10, | ||
363 | sort: '-createdAt' | ||
364 | }) | ||
365 | .then(res => { | ||
366 | if (res.body.total > 0) pendingRequests = true | ||
367 | }) | ||
368 | tasks.push(p) | ||
369 | } | ||
370 | } | ||
371 | |||
372 | await Promise.all(tasks) | ||
373 | |||
374 | return pendingRequests | ||
375 | } | ||
diff --git a/server/tools/cli.ts b/server/tools/cli.ts index 58e2445ac..d1a631b69 100644 --- a/server/tools/cli.ts +++ b/server/tools/cli.ts | |||
@@ -6,6 +6,9 @@ import { getVideoChannel } from '../../shared/extra-utils/videos/video-channels' | |||
6 | import { Command } from 'commander' | 6 | import { Command } from 'commander' |
7 | import { VideoChannel, VideoPrivacy } from '../../shared/models/videos' | 7 | import { VideoChannel, VideoPrivacy } from '../../shared/models/videos' |
8 | import { createLogger, format, transports } from 'winston' | 8 | import { createLogger, format, transports } from 'winston' |
9 | import { getMyUserInformation } from '@shared/extra-utils/users/users' | ||
10 | import { User, UserRole } from '@shared/models' | ||
11 | import { getAccessToken } from '@shared/extra-utils/users/login' | ||
9 | 12 | ||
10 | let configName = 'PeerTube/CLI' | 13 | let configName = 'PeerTube/CLI' |
11 | if (isTestInstance()) configName += `-${getAppNumber()}` | 14 | if (isTestInstance()) configName += `-${getAppNumber()}` |
@@ -14,8 +17,21 @@ const config = require('application-config')(configName) | |||
14 | 17 | ||
15 | const version = require('../../../package.json').version | 18 | const version = require('../../../package.json').version |
16 | 19 | ||
20 | async function getAdminTokenOrDie (url: string, username: string, password: string) { | ||
21 | const accessToken = await getAccessToken(url, username, password) | ||
22 | const resMe = await getMyUserInformation(url, accessToken) | ||
23 | const me: User = resMe.body | ||
24 | |||
25 | if (me.role !== UserRole.ADMINISTRATOR) { | ||
26 | console.error('You must be an administrator.') | ||
27 | process.exit(-1) | ||
28 | } | ||
29 | |||
30 | return accessToken | ||
31 | } | ||
32 | |||
17 | interface Settings { | 33 | interface Settings { |
18 | remotes: any[], | 34 | remotes: any[] |
19 | default: number | 35 | default: number |
20 | } | 36 | } |
21 | 37 | ||
@@ -74,9 +90,9 @@ function getRemoteObjectOrDie ( | |||
74 | if (!program['url'] || !program['username'] || !program['password']) { | 90 | if (!program['url'] || !program['username'] || !program['password']) { |
75 | // No remote and we don't have program parameters: quit | 91 | // No remote and we don't have program parameters: quit |
76 | if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) { | 92 | if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) { |
77 | if (!program[ 'url' ]) console.error('--url field is required.') | 93 | if (!program['url']) console.error('--url field is required.') |
78 | if (!program[ 'username' ]) console.error('--username field is required.') | 94 | if (!program['username']) console.error('--username field is required.') |
79 | if (!program[ 'password' ]) console.error('--password field is required.') | 95 | if (!program['password']) console.error('--password field is required.') |
80 | 96 | ||
81 | return process.exit(-1) | 97 | return process.exit(-1) |
82 | } | 98 | } |
@@ -96,9 +112,9 @@ function getRemoteObjectOrDie ( | |||
96 | } | 112 | } |
97 | 113 | ||
98 | return { | 114 | return { |
99 | url: program[ 'url' ], | 115 | url: program['url'], |
100 | username: program[ 'username' ], | 116 | username: program['username'], |
101 | password: program[ 'password' ] | 117 | password: program['password'] |
102 | } | 118 | } |
103 | } | 119 | } |
104 | 120 | ||
@@ -134,8 +150,8 @@ async function buildVideoAttributesFromCommander (url: string, command: Command, | |||
134 | const booleanAttributes: { [id in keyof typeof defaultBooleanAttributes]: boolean } | {} = {} | 150 | const booleanAttributes: { [id in keyof typeof defaultBooleanAttributes]: boolean } | {} = {} |
135 | 151 | ||
136 | for (const key of Object.keys(defaultBooleanAttributes)) { | 152 | for (const key of Object.keys(defaultBooleanAttributes)) { |
137 | if (command[ key ] !== undefined) { | 153 | if (command[key] !== undefined) { |
138 | booleanAttributes[key] = command[ key ] | 154 | booleanAttributes[key] = command[key] |
139 | } else if (defaultAttributes[key] !== undefined) { | 155 | } else if (defaultAttributes[key] !== undefined) { |
140 | booleanAttributes[key] = defaultAttributes[key] | 156 | booleanAttributes[key] = defaultAttributes[key] |
141 | } else { | 157 | } else { |
@@ -144,19 +160,19 @@ async function buildVideoAttributesFromCommander (url: string, command: Command, | |||
144 | } | 160 | } |
145 | 161 | ||
146 | const videoAttributes = { | 162 | const videoAttributes = { |
147 | name: command[ 'videoName' ] || defaultAttributes.name, | 163 | name: command['videoName'] || defaultAttributes.name, |
148 | category: command[ 'category' ] || defaultAttributes.category || undefined, | 164 | category: command['category'] || defaultAttributes.category || undefined, |
149 | licence: command[ 'licence' ] || defaultAttributes.licence || undefined, | 165 | licence: command['licence'] || defaultAttributes.licence || undefined, |
150 | language: command[ 'language' ] || defaultAttributes.language || undefined, | 166 | language: command['language'] || defaultAttributes.language || undefined, |
151 | privacy: command[ 'privacy' ] || defaultAttributes.privacy || VideoPrivacy.PUBLIC, | 167 | privacy: command['privacy'] || defaultAttributes.privacy || VideoPrivacy.PUBLIC, |
152 | support: command[ 'support' ] || defaultAttributes.support || undefined, | 168 | support: command['support'] || defaultAttributes.support || undefined, |
153 | description: command[ 'videoDescription' ] || defaultAttributes.description || undefined, | 169 | description: command['videoDescription'] || defaultAttributes.description || undefined, |
154 | tags: command[ 'tags' ] || defaultAttributes.tags || undefined | 170 | tags: command['tags'] || defaultAttributes.tags || undefined |
155 | } | 171 | } |
156 | 172 | ||
157 | Object.assign(videoAttributes, booleanAttributes) | 173 | Object.assign(videoAttributes, booleanAttributes) |
158 | 174 | ||
159 | if (command[ 'channelName' ]) { | 175 | if (command['channelName']) { |
160 | const res = await getVideoChannel(url, command['channelName']) | 176 | const res = await getVideoChannel(url, command['channelName']) |
161 | const videoChannel: VideoChannel = res.body | 177 | const videoChannel: VideoChannel = res.body |
162 | 178 | ||
@@ -172,9 +188,9 @@ async function buildVideoAttributesFromCommander (url: string, command: Command, | |||
172 | 188 | ||
173 | function getServerCredentials (program: any) { | 189 | function getServerCredentials (program: any) { |
174 | return Promise.all([ getSettings(), getNetrc() ]) | 190 | return Promise.all([ getSettings(), getNetrc() ]) |
175 | .then(([ settings, netrc ]) => { | 191 | .then(([ settings, netrc ]) => { |
176 | return getRemoteObjectOrDie(program, settings, netrc) | 192 | return getRemoteObjectOrDie(program, settings, netrc) |
177 | }) | 193 | }) |
178 | } | 194 | } |
179 | 195 | ||
180 | function getLogger (logLevel = 'info') { | 196 | function getLogger (logLevel = 'info') { |
@@ -222,5 +238,7 @@ export { | |||
222 | getServerCredentials, | 238 | getServerCredentials, |
223 | 239 | ||
224 | buildCommonVideoOptions, | 240 | buildCommonVideoOptions, |
225 | buildVideoAttributesFromCommander | 241 | buildVideoAttributesFromCommander, |
242 | |||
243 | getAdminTokenOrDie | ||
226 | } | 244 | } |
diff --git a/server/tools/package.json b/server/tools/package.json index 40959d76e..06ad31cab 100644 --- a/server/tools/package.json +++ b/server/tools/package.json | |||
@@ -4,11 +4,12 @@ | |||
4 | "private": true, | 4 | "private": true, |
5 | "dependencies": { | 5 | "dependencies": { |
6 | "application-config": "^1.0.1", | 6 | "application-config": "^1.0.1", |
7 | "cli-table": "^0.3.1", | 7 | "cli-table3": "^0.5.1", |
8 | "netrc-parser": "^3.1.6", | 8 | "netrc-parser": "^3.1.6", |
9 | "webtorrent-hybrid": "^4.0.1" | 9 | "webtorrent-hybrid": "^4.0.1" |
10 | }, | 10 | }, |
11 | "summon": { | 11 | "summon": { |
12 | "silent": true | 12 | "silent": true |
13 | } | 13 | }, |
14 | "devDependencies": {} | ||
14 | } | 15 | } |
diff --git a/server/tools/peertube-auth.ts b/server/tools/peertube-auth.ts index 6597a5c36..6b486e575 100644 --- a/server/tools/peertube-auth.ts +++ b/server/tools/peertube-auth.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | // eslint-disable @typescript-eslint/no-unnecessary-type-assertion | ||
2 | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | 3 | import { registerTSPaths } from '../helpers/register-ts-paths' |
2 | registerTSPaths() | 4 | registerTSPaths() |
3 | 5 | ||
@@ -5,9 +7,8 @@ import * as program from 'commander' | |||
5 | import * as prompt from 'prompt' | 7 | import * as prompt from 'prompt' |
6 | import { getNetrc, getSettings, writeSettings } from './cli' | 8 | import { getNetrc, getSettings, writeSettings } from './cli' |
7 | import { isUserUsernameValid } from '../helpers/custom-validators/users' | 9 | import { isUserUsernameValid } from '../helpers/custom-validators/users' |
8 | import { getAccessToken, login } from '../../shared/extra-utils' | 10 | import { getAccessToken } from '../../shared/extra-utils' |
9 | 11 | import * as CliTable3 from 'cli-table3' | |
10 | const Table = require('cli-table') | ||
11 | 12 | ||
12 | async function delInstance (url: string) { | 13 | async function delInstance (url: string) { |
13 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) | 14 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) |
@@ -108,10 +109,10 @@ program | |||
108 | .action(async () => { | 109 | .action(async () => { |
109 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) | 110 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) |
110 | 111 | ||
111 | const table = new Table({ | 112 | const table = new CliTable3({ |
112 | head: ['instance', 'login'], | 113 | head: [ 'instance', 'login' ], |
113 | colWidths: [30, 30] | 114 | colWidths: [ 30, 30 ] |
114 | }) | 115 | }) as any |
115 | 116 | ||
116 | settings.remotes.forEach(element => { | 117 | settings.remotes.forEach(element => { |
117 | if (!netrc.machines[element]) return | 118 | if (!netrc.machines[element]) return |
diff --git a/server/tools/peertube-import-videos.ts b/server/tools/peertube-import-videos.ts index eaa792763..0efe87810 100644 --- a/server/tools/peertube-import-videos.ts +++ b/server/tools/peertube-import-videos.ts | |||
@@ -1,10 +1,6 @@ | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | 1 | import { registerTSPaths } from '../helpers/register-ts-paths' |
2 | |||
3 | registerTSPaths() | 2 | registerTSPaths() |
4 | 3 | ||
5 | // FIXME: https://github.com/nodejs/node/pull/16853 | ||
6 | require('tls').DEFAULT_ECDH_CURVE = 'auto' | ||
7 | |||
8 | import * as program from 'commander' | 4 | import * as program from 'commander' |
9 | import { join } from 'path' | 5 | import { join } from 'path' |
10 | import { doRequestAndSaveToFile } from '../helpers/requests' | 6 | import { doRequestAndSaveToFile } from '../helpers/requests' |
@@ -16,7 +12,7 @@ import { accessSync, constants } from 'fs' | |||
16 | import { remove } from 'fs-extra' | 12 | import { remove } from 'fs-extra' |
17 | import { sha256 } from '../helpers/core-utils' | 13 | import { sha256 } from '../helpers/core-utils' |
18 | import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl' | 14 | import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl' |
19 | import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getServerCredentials, getLogger } from './cli' | 15 | import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getLogger, getServerCredentials } from './cli' |
20 | 16 | ||
21 | type UserInfo = { | 17 | type UserInfo = { |
22 | username: string | 18 | username: string |
@@ -44,30 +40,29 @@ command | |||
44 | .option('-T, --tmpdir <tmpdir>', 'Working directory', __dirname) | 40 | .option('-T, --tmpdir <tmpdir>', 'Working directory', __dirname) |
45 | .parse(process.argv) | 41 | .parse(process.argv) |
46 | 42 | ||
47 | let log = getLogger(program[ 'verbose' ]) | 43 | const log = getLogger(program['verbose']) |
48 | 44 | ||
49 | getServerCredentials(command) | 45 | getServerCredentials(command) |
50 | .then(({ url, username, password }) => { | 46 | .then(({ url, username, password }) => { |
51 | if (!program[ 'targetUrl' ]) { | 47 | if (!program['targetUrl']) { |
52 | exitError('--target-url field is required.') | 48 | exitError('--target-url field is required.') |
53 | } | 49 | } |
54 | 50 | ||
55 | try { | 51 | try { |
56 | accessSync(program[ 'tmpdir' ], constants.R_OK | constants.W_OK) | 52 | accessSync(program['tmpdir'], constants.R_OK | constants.W_OK) |
57 | } catch (e) { | 53 | } catch (e) { |
58 | exitError('--tmpdir %s: directory does not exist or is not accessible', program[ 'tmpdir' ]) | 54 | exitError('--tmpdir %s: directory does not exist or is not accessible', program['tmpdir']) |
59 | } | 55 | } |
60 | 56 | ||
61 | url = normalizeTargetUrl(url) | 57 | url = normalizeTargetUrl(url) |
62 | program[ 'targetUrl' ] = normalizeTargetUrl(program[ 'targetUrl' ]) | 58 | program['targetUrl'] = normalizeTargetUrl(program['targetUrl']) |
63 | 59 | ||
64 | const user = { username, password } | 60 | const user = { username, password } |
65 | 61 | ||
66 | run(url, user) | 62 | run(url, user) |
67 | .catch(err => { | 63 | .catch(err => exitError(err)) |
68 | exitError(err) | ||
69 | }) | ||
70 | }) | 64 | }) |
65 | .catch(err => console.error(err)) | ||
71 | 66 | ||
72 | async function run (url: string, user: UserInfo) { | 67 | async function run (url: string, user: UserInfo) { |
73 | if (!user.password) { | 68 | if (!user.password) { |
@@ -77,7 +72,7 @@ async function run (url: string, user: UserInfo) { | |||
77 | const youtubeDL = await safeGetYoutubeDL() | 72 | const youtubeDL = await safeGetYoutubeDL() |
78 | 73 | ||
79 | const options = [ '-j', '--flat-playlist', '--playlist-reverse' ] | 74 | const options = [ '-j', '--flat-playlist', '--playlist-reverse' ] |
80 | youtubeDL.getInfo(program[ 'targetUrl' ], options, processOptions, async (err, info) => { | 75 | youtubeDL.getInfo(program['targetUrl'], options, processOptions, async (err, info) => { |
81 | if (err) { | 76 | if (err) { |
82 | exitError(err.message) | 77 | exitError(err.message) |
83 | } | 78 | } |
@@ -86,10 +81,10 @@ async function run (url: string, user: UserInfo) { | |||
86 | 81 | ||
87 | // Normalize utf8 fields | 82 | // Normalize utf8 fields |
88 | infoArray = [].concat(info) | 83 | infoArray = [].concat(info) |
89 | if (program[ 'first' ]) { | 84 | if (program['first']) { |
90 | infoArray = infoArray.slice(0, program[ 'first' ]) | 85 | infoArray = infoArray.slice(0, program['first']) |
91 | } else if (program[ 'last' ]) { | 86 | } else if (program['last']) { |
92 | infoArray = infoArray.slice(-program[ 'last' ]) | 87 | infoArray = infoArray.slice(-program['last']) |
93 | } | 88 | } |
94 | infoArray = infoArray.map(i => normalizeObject(i)) | 89 | infoArray = infoArray.map(i => normalizeObject(i)) |
95 | 90 | ||
@@ -97,22 +92,22 @@ async function run (url: string, user: UserInfo) { | |||
97 | 92 | ||
98 | for (const info of infoArray) { | 93 | for (const info of infoArray) { |
99 | await processVideo({ | 94 | await processVideo({ |
100 | cwd: program[ 'tmpdir' ], | 95 | cwd: program['tmpdir'], |
101 | url, | 96 | url, |
102 | user, | 97 | user, |
103 | youtubeInfo: info | 98 | youtubeInfo: info |
104 | }) | 99 | }) |
105 | } | 100 | } |
106 | 101 | ||
107 | log.info('Video/s for user %s imported: %s', user.username, program[ 'targetUrl' ]) | 102 | log.info('Video/s for user %s imported: %s', user.username, program['targetUrl']) |
108 | process.exit(0) | 103 | process.exit(0) |
109 | }) | 104 | }) |
110 | } | 105 | } |
111 | 106 | ||
112 | function processVideo (parameters: { | 107 | function processVideo (parameters: { |
113 | cwd: string, | 108 | cwd: string |
114 | url: string, | 109 | url: string |
115 | user: { username: string, password: string }, | 110 | user: { username: string, password: string } |
116 | youtubeInfo: any | 111 | youtubeInfo: any |
117 | }) { | 112 | }) { |
118 | const { youtubeInfo, cwd, url, user } = parameters | 113 | const { youtubeInfo, cwd, url, user } = parameters |
@@ -123,17 +118,17 @@ function processVideo (parameters: { | |||
123 | const videoInfo = await fetchObject(youtubeInfo) | 118 | const videoInfo = await fetchObject(youtubeInfo) |
124 | log.debug('Fetched object.', videoInfo) | 119 | log.debug('Fetched object.', videoInfo) |
125 | 120 | ||
126 | if (program[ 'since' ]) { | 121 | if (program['since']) { |
127 | if (buildOriginallyPublishedAt(videoInfo).getTime() < program[ 'since' ].getTime()) { | 122 | if (buildOriginallyPublishedAt(videoInfo).getTime() < program['since'].getTime()) { |
128 | log.info('Video "%s" has been published before "%s", don\'t upload it.\n', | 123 | log.info('Video "%s" has been published before "%s", don\'t upload it.\n', |
129 | videoInfo.title, formatDate(program[ 'since' ])) | 124 | videoInfo.title, formatDate(program['since'])) |
130 | return res() | 125 | return res() |
131 | } | 126 | } |
132 | } | 127 | } |
133 | if (program[ 'until' ]) { | 128 | if (program['until']) { |
134 | if (buildOriginallyPublishedAt(videoInfo).getTime() > program[ 'until' ].getTime()) { | 129 | if (buildOriginallyPublishedAt(videoInfo).getTime() > program['until'].getTime()) { |
135 | log.info('Video "%s" has been published after "%s", don\'t upload it.\n', | 130 | log.info('Video "%s" has been published after "%s", don\'t upload it.\n', |
136 | videoInfo.title, formatDate(program[ 'until' ])) | 131 | videoInfo.title, formatDate(program['until'])) |
137 | return res() | 132 | return res() |
138 | } | 133 | } |
139 | } | 134 | } |
@@ -178,11 +173,11 @@ function processVideo (parameters: { | |||
178 | } | 173 | } |
179 | 174 | ||
180 | async function uploadVideoOnPeerTube (parameters: { | 175 | async function uploadVideoOnPeerTube (parameters: { |
181 | videoInfo: any, | 176 | videoInfo: any |
182 | videoPath: string, | 177 | videoPath: string |
183 | cwd: string, | 178 | cwd: string |
184 | url: string, | 179 | url: string |
185 | user: { username: string; password: string } | 180 | user: { username: string, password: string } |
186 | }) { | 181 | }) { |
187 | const { videoInfo, videoPath, cwd, url, user } = parameters | 182 | const { videoInfo, videoPath, cwd, url, user } = parameters |
188 | 183 | ||
@@ -210,9 +205,9 @@ async function uploadVideoOnPeerTube (parameters: { | |||
210 | 205 | ||
211 | const defaultAttributes = { | 206 | const defaultAttributes = { |
212 | name: truncate(videoInfo.title, { | 207 | name: truncate(videoInfo.title, { |
213 | 'length': CONSTRAINTS_FIELDS.VIDEOS.NAME.max, | 208 | length: CONSTRAINTS_FIELDS.VIDEOS.NAME.max, |
214 | 'separator': /,? +/, | 209 | separator: /,? +/, |
215 | 'omission': ' […]' | 210 | omission: ' […]' |
216 | }), | 211 | }), |
217 | category, | 212 | category, |
218 | licence, | 213 | licence, |
@@ -259,7 +254,7 @@ async function uploadVideoOnPeerTube (parameters: { | |||
259 | async function getCategory (categories: string[], url: string) { | 254 | async function getCategory (categories: string[], url: string) { |
260 | if (!categories) return undefined | 255 | if (!categories) return undefined |
261 | 256 | ||
262 | const categoryString = categories[ 0 ] | 257 | const categoryString = categories[0] |
263 | 258 | ||
264 | if (categoryString === 'News & Politics') return 11 | 259 | if (categoryString === 'News & Politics') return 11 |
265 | 260 | ||
@@ -267,7 +262,7 @@ async function getCategory (categories: string[], url: string) { | |||
267 | const categoriesServer = res.body | 262 | const categoriesServer = res.body |
268 | 263 | ||
269 | for (const key of Object.keys(categoriesServer)) { | 264 | for (const key of Object.keys(categoriesServer)) { |
270 | const categoryServer = categoriesServer[ key ] | 265 | const categoryServer = categoriesServer[key] |
271 | if (categoryString.toLowerCase() === categoryServer.toLowerCase()) return parseInt(key, 10) | 266 | if (categoryString.toLowerCase() === categoryServer.toLowerCase()) return parseInt(key, 10) |
272 | } | 267 | } |
273 | 268 | ||
@@ -289,12 +284,12 @@ function normalizeObject (obj: any) { | |||
289 | // Deprecated key | 284 | // Deprecated key |
290 | if (key === 'resolution') continue | 285 | if (key === 'resolution') continue |
291 | 286 | ||
292 | const value = obj[ key ] | 287 | const value = obj[key] |
293 | 288 | ||
294 | if (typeof value === 'string') { | 289 | if (typeof value === 'string') { |
295 | newObj[ key ] = value.normalize() | 290 | newObj[key] = value.normalize() |
296 | } else { | 291 | } else { |
297 | newObj[ key ] = value | 292 | newObj[key] = value |
298 | } | 293 | } |
299 | } | 294 | } |
300 | 295 | ||
@@ -306,7 +301,7 @@ function fetchObject (info: any) { | |||
306 | 301 | ||
307 | return new Promise<any>(async (res, rej) => { | 302 | return new Promise<any>(async (res, rej) => { |
308 | const youtubeDL = await safeGetYoutubeDL() | 303 | const youtubeDL = await safeGetYoutubeDL() |
309 | youtubeDL.getInfo(url, undefined, processOptions, async (err, videoInfo) => { | 304 | youtubeDL.getInfo(url, undefined, processOptions, (err, videoInfo) => { |
310 | if (err) return rej(err) | 305 | if (err) return rej(err) |
311 | 306 | ||
312 | const videoInfoWithUrl = Object.assign(videoInfo, { url }) | 307 | const videoInfoWithUrl = Object.assign(videoInfo, { url }) |
@@ -317,10 +312,10 @@ function fetchObject (info: any) { | |||
317 | 312 | ||
318 | function buildUrl (info: any) { | 313 | function buildUrl (info: any) { |
319 | const webpageUrl = info.webpage_url as string | 314 | const webpageUrl = info.webpage_url as string |
320 | if (webpageUrl && webpageUrl.match(/^https?:\/\//)) return webpageUrl | 315 | if (webpageUrl?.match(/^https?:\/\//)) return webpageUrl |
321 | 316 | ||
322 | const url = info.url as string | 317 | const url = info.url as string |
323 | if (url && url.match(/^https?:\/\//)) return url | 318 | if (url?.match(/^https?:\/\//)) return url |
324 | 319 | ||
325 | // It seems youtube-dl does not return the video url | 320 | // It seems youtube-dl does not return the video url |
326 | return 'https://www.youtube.com/watch?v=' + info.id | 321 | return 'https://www.youtube.com/watch?v=' + info.id |
@@ -388,7 +383,7 @@ function parseDate (dateAsStr: string): Date { | |||
388 | } | 383 | } |
389 | 384 | ||
390 | function formatDate (date: Date): string { | 385 | function formatDate (date: Date): string { |
391 | return date.toISOString().split('T')[ 0 ] | 386 | return date.toISOString().split('T')[0] |
392 | } | 387 | } |
393 | 388 | ||
394 | function exitError (message: string, ...meta: any[]) { | 389 | function exitError (message: string, ...meta: any[]) { |
diff --git a/server/tools/peertube-plugins.ts b/server/tools/peertube-plugins.ts index e40606107..05b75fab2 100644 --- a/server/tools/peertube-plugins.ts +++ b/server/tools/peertube-plugins.ts | |||
@@ -1,17 +1,15 @@ | |||
1 | // eslint-disable @typescript-eslint/no-unnecessary-type-assertion | ||
2 | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | 3 | import { registerTSPaths } from '../helpers/register-ts-paths' |
2 | registerTSPaths() | 4 | registerTSPaths() |
3 | 5 | ||
4 | import * as program from 'commander' | 6 | import * as program from 'commander' |
5 | import { PluginType } from '../../shared/models/plugins/plugin.type' | 7 | import { PluginType } from '../../shared/models/plugins/plugin.type' |
6 | import { getAccessToken } from '../../shared/extra-utils/users/login' | ||
7 | import { getMyUserInformation } from '../../shared/extra-utils/users/users' | ||
8 | import { installPlugin, listPlugins, uninstallPlugin, updatePlugin } from '../../shared/extra-utils/server/plugins' | 8 | import { installPlugin, listPlugins, uninstallPlugin, updatePlugin } from '../../shared/extra-utils/server/plugins' |
9 | import { getServerCredentials } from './cli' | 9 | import { getAdminTokenOrDie, getServerCredentials } from './cli' |
10 | import { User, UserRole } from '../../shared/models/users' | ||
11 | import { PeerTubePlugin } from '../../shared/models/plugins/peertube-plugin.model' | 10 | import { PeerTubePlugin } from '../../shared/models/plugins/peertube-plugin.model' |
12 | import { isAbsolute } from 'path' | 11 | import { isAbsolute } from 'path' |
13 | 12 | import * as CliTable3 from 'cli-table3' | |
14 | const Table = require('cli-table') | ||
15 | 13 | ||
16 | program | 14 | program |
17 | .name('plugins') | 15 | .name('plugins') |
@@ -82,10 +80,10 @@ async function pluginsListCLI () { | |||
82 | }) | 80 | }) |
83 | const plugins: PeerTubePlugin[] = res.body.data | 81 | const plugins: PeerTubePlugin[] = res.body.data |
84 | 82 | ||
85 | const table = new Table({ | 83 | const table = new CliTable3({ |
86 | head: ['name', 'version', 'homepage'], | 84 | head: [ 'name', 'version', 'homepage' ], |
87 | colWidths: [ 50, 10, 50 ] | 85 | colWidths: [ 50, 10, 50 ] |
88 | }) | 86 | }) as any |
89 | 87 | ||
90 | for (const plugin of plugins) { | 88 | for (const plugin of plugins) { |
91 | const npmName = plugin.type === PluginType.PLUGIN | 89 | const npmName = plugin.type === PluginType.PLUGIN |
@@ -128,7 +126,6 @@ async function installPluginCLI (options: any) { | |||
128 | } catch (err) { | 126 | } catch (err) { |
129 | console.error('Cannot install plugin.', err) | 127 | console.error('Cannot install plugin.', err) |
130 | process.exit(-1) | 128 | process.exit(-1) |
131 | return | ||
132 | } | 129 | } |
133 | 130 | ||
134 | console.log('Plugin installed.') | 131 | console.log('Plugin installed.') |
@@ -160,7 +157,6 @@ async function updatePluginCLI (options: any) { | |||
160 | } catch (err) { | 157 | } catch (err) { |
161 | console.error('Cannot update plugin.', err) | 158 | console.error('Cannot update plugin.', err) |
162 | process.exit(-1) | 159 | process.exit(-1) |
163 | return | ||
164 | } | 160 | } |
165 | 161 | ||
166 | console.log('Plugin updated.') | 162 | console.log('Plugin updated.') |
@@ -181,27 +177,13 @@ async function uninstallPluginCLI (options: any) { | |||
181 | await uninstallPlugin({ | 177 | await uninstallPlugin({ |
182 | url, | 178 | url, |
183 | accessToken, | 179 | accessToken, |
184 | npmName: options[ 'npmName' ] | 180 | npmName: options['npmName'] |
185 | }) | 181 | }) |
186 | } catch (err) { | 182 | } catch (err) { |
187 | console.error('Cannot uninstall plugin.', err) | 183 | console.error('Cannot uninstall plugin.', err) |
188 | process.exit(-1) | 184 | process.exit(-1) |
189 | return | ||
190 | } | 185 | } |
191 | 186 | ||
192 | console.log('Plugin uninstalled.') | 187 | console.log('Plugin uninstalled.') |
193 | process.exit(0) | 188 | process.exit(0) |
194 | } | 189 | } |
195 | |||
196 | async function getAdminTokenOrDie (url: string, username: string, password: string) { | ||
197 | const accessToken = await getAccessToken(url, username, password) | ||
198 | const resMe = await getMyUserInformation(url, accessToken) | ||
199 | const me: User = resMe.body | ||
200 | |||
201 | if (me.role !== UserRole.ADMINISTRATOR) { | ||
202 | console.error('Cannot list plugins if you are not administrator.') | ||
203 | process.exit(-1) | ||
204 | } | ||
205 | |||
206 | return accessToken | ||
207 | } | ||
diff --git a/server/tools/peertube-redundancy.ts b/server/tools/peertube-redundancy.ts new file mode 100644 index 000000000..1ab58a438 --- /dev/null +++ b/server/tools/peertube-redundancy.ts | |||
@@ -0,0 +1,197 @@ | |||
1 | // eslint-disable @typescript-eslint/no-unnecessary-type-assertion | ||
2 | |||
3 | import { registerTSPaths } from '../helpers/register-ts-paths' | ||
4 | registerTSPaths() | ||
5 | |||
6 | import * as program from 'commander' | ||
7 | import { getAdminTokenOrDie, getServerCredentials } from './cli' | ||
8 | import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' | ||
9 | import { addVideoRedundancy, listVideoRedundancies, removeVideoRedundancy } from '@shared/extra-utils/server/redundancy' | ||
10 | import validator from 'validator' | ||
11 | import * as CliTable3 from 'cli-table3' | ||
12 | import { URL } from 'url' | ||
13 | import { uniq } from 'lodash' | ||
14 | |||
15 | import bytes = require('bytes') | ||
16 | |||
17 | program | ||
18 | .name('plugins') | ||
19 | .usage('[command] [options]') | ||
20 | |||
21 | program | ||
22 | .command('list-remote-redundancies') | ||
23 | .description('List remote redundancies on your videos') | ||
24 | .option('-u, --url <url>', 'Server url') | ||
25 | .option('-U, --username <username>', 'Username') | ||
26 | .option('-p, --password <token>', 'Password') | ||
27 | .action(() => listRedundanciesCLI('my-videos')) | ||
28 | |||
29 | program | ||
30 | .command('list-my-redundancies') | ||
31 | .description('List your redundancies of remote videos') | ||
32 | .option('-u, --url <url>', 'Server url') | ||
33 | .option('-U, --username <username>', 'Username') | ||
34 | .option('-p, --password <token>', 'Password') | ||
35 | .action(() => listRedundanciesCLI('remote-videos')) | ||
36 | |||
37 | program | ||
38 | .command('add') | ||
39 | .description('Duplicate a video in your redundancy system') | ||
40 | .option('-u, --url <url>', 'Server url') | ||
41 | .option('-U, --username <username>', 'Username') | ||
42 | .option('-p, --password <token>', 'Password') | ||
43 | .option('-v, --video <videoId>', 'Video id to duplicate') | ||
44 | .action((options) => addRedundancyCLI(options)) | ||
45 | |||
46 | program | ||
47 | .command('remove') | ||
48 | .description('Remove a video from your redundancies') | ||
49 | .option('-u, --url <url>', 'Server url') | ||
50 | .option('-U, --username <username>', 'Username') | ||
51 | .option('-p, --password <token>', 'Password') | ||
52 | .option('-v, --video <videoId>', 'Video id to remove from redundancies') | ||
53 | .action((options) => removeRedundancyCLI(options)) | ||
54 | |||
55 | if (!process.argv.slice(2).length) { | ||
56 | program.outputHelp() | ||
57 | } | ||
58 | |||
59 | program.parse(process.argv) | ||
60 | |||
61 | // ---------------------------------------------------------------------------- | ||
62 | |||
63 | async function listRedundanciesCLI (target: VideoRedundanciesTarget) { | ||
64 | const { url, username, password } = await getServerCredentials(program) | ||
65 | const accessToken = await getAdminTokenOrDie(url, username, password) | ||
66 | |||
67 | const redundancies = await listVideoRedundanciesData(url, accessToken, target) | ||
68 | |||
69 | const table = new CliTable3({ | ||
70 | head: [ 'video id', 'video name', 'video url', 'files', 'playlists', 'by instances', 'total size' ] | ||
71 | }) as any | ||
72 | |||
73 | for (const redundancy of redundancies) { | ||
74 | const webtorrentFiles = redundancy.redundancies.files | ||
75 | const streamingPlaylists = redundancy.redundancies.streamingPlaylists | ||
76 | |||
77 | let totalSize = '' | ||
78 | if (target === 'remote-videos') { | ||
79 | const tmp = webtorrentFiles.concat(streamingPlaylists) | ||
80 | .reduce((a, b) => a + b.size, 0) | ||
81 | |||
82 | totalSize = bytes(tmp) | ||
83 | } | ||
84 | |||
85 | const instances = uniq( | ||
86 | webtorrentFiles.concat(streamingPlaylists) | ||
87 | .map(r => r.fileUrl) | ||
88 | .map(u => new URL(u).host) | ||
89 | ) | ||
90 | |||
91 | table.push([ | ||
92 | redundancy.id.toString(), | ||
93 | redundancy.name, | ||
94 | redundancy.url, | ||
95 | webtorrentFiles.length, | ||
96 | streamingPlaylists.length, | ||
97 | instances.join('\n'), | ||
98 | totalSize | ||
99 | ]) | ||
100 | } | ||
101 | |||
102 | console.log(table.toString()) | ||
103 | process.exit(0) | ||
104 | } | ||
105 | |||
106 | async function addRedundancyCLI (options: { videoId: number }) { | ||
107 | const { url, username, password } = await getServerCredentials(program) | ||
108 | const accessToken = await getAdminTokenOrDie(url, username, password) | ||
109 | |||
110 | if (!options['video'] || validator.isInt('' + options['video']) === false) { | ||
111 | console.error('You need to specify the video id to duplicate and it should be a number.\n') | ||
112 | program.outputHelp() | ||
113 | process.exit(-1) | ||
114 | } | ||
115 | |||
116 | try { | ||
117 | await addVideoRedundancy({ | ||
118 | url, | ||
119 | accessToken, | ||
120 | videoId: options['video'] | ||
121 | }) | ||
122 | |||
123 | console.log('Video will be duplicated by your instance!') | ||
124 | |||
125 | process.exit(0) | ||
126 | } catch (err) { | ||
127 | if (err.message.includes(409)) { | ||
128 | console.error('This video is already duplicated by your instance.') | ||
129 | } else if (err.message.includes(404)) { | ||
130 | console.error('This video id does not exist.') | ||
131 | } else { | ||
132 | console.error(err) | ||
133 | } | ||
134 | |||
135 | process.exit(-1) | ||
136 | } | ||
137 | } | ||
138 | |||
139 | async function removeRedundancyCLI (options: { videoId: number }) { | ||
140 | const { url, username, password } = await getServerCredentials(program) | ||
141 | const accessToken = await getAdminTokenOrDie(url, username, password) | ||
142 | |||
143 | if (!options['video'] || validator.isInt('' + options['video']) === false) { | ||
144 | console.error('You need to specify the video id to remove from your redundancies.\n') | ||
145 | program.outputHelp() | ||
146 | process.exit(-1) | ||
147 | } | ||
148 | |||
149 | const videoId = parseInt(options['video'] + '', 10) | ||
150 | |||
151 | let redundancies = await listVideoRedundanciesData(url, accessToken, 'my-videos') | ||
152 | let videoRedundancy = redundancies.find(r => videoId === r.id) | ||
153 | |||
154 | if (!videoRedundancy) { | ||
155 | redundancies = await listVideoRedundanciesData(url, accessToken, 'remote-videos') | ||
156 | videoRedundancy = redundancies.find(r => videoId === r.id) | ||
157 | } | ||
158 | |||
159 | if (!videoRedundancy) { | ||
160 | console.error('Video redundancy not found.') | ||
161 | process.exit(-1) | ||
162 | } | ||
163 | |||
164 | try { | ||
165 | const ids = videoRedundancy.redundancies.files | ||
166 | .concat(videoRedundancy.redundancies.streamingPlaylists) | ||
167 | .map(r => r.id) | ||
168 | |||
169 | for (const id of ids) { | ||
170 | await removeVideoRedundancy({ | ||
171 | url, | ||
172 | accessToken, | ||
173 | redundancyId: id | ||
174 | }) | ||
175 | } | ||
176 | |||
177 | console.log('Video redundancy removed!') | ||
178 | |||
179 | process.exit(0) | ||
180 | } catch (err) { | ||
181 | console.error(err) | ||
182 | process.exit(-1) | ||
183 | } | ||
184 | } | ||
185 | |||
186 | async function listVideoRedundanciesData (url: string, accessToken: string, target: VideoRedundanciesTarget) { | ||
187 | const res = await listVideoRedundancies({ | ||
188 | url, | ||
189 | accessToken, | ||
190 | start: 0, | ||
191 | count: 100, | ||
192 | sort: 'name', | ||
193 | target | ||
194 | }) | ||
195 | |||
196 | return res.body.data as VideoRedundancy[] | ||
197 | } | ||
diff --git a/server/tools/peertube-repl.ts b/server/tools/peertube-repl.ts index ab6e215d9..7c936ae0d 100644 --- a/server/tools/peertube-repl.ts +++ b/server/tools/peertube-repl.ts | |||
@@ -1,6 +1,4 @@ | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | 1 | import { registerTSPaths } from '../helpers/register-ts-paths' |
2 | registerTSPaths() | ||
3 | |||
4 | import * as repl from 'repl' | 2 | import * as repl from 'repl' |
5 | import * as path from 'path' | 3 | import * as path from 'path' |
6 | import * as _ from 'lodash' | 4 | import * as _ from 'lodash' |
@@ -23,6 +21,8 @@ import * as signupUtils from '../helpers/signup' | |||
23 | import * as utils from '../helpers/utils' | 21 | import * as utils from '../helpers/utils' |
24 | import * as YoutubeDLUtils from '../helpers/youtube-dl' | 22 | import * as YoutubeDLUtils from '../helpers/youtube-dl' |
25 | 23 | ||
24 | registerTSPaths() | ||
25 | |||
26 | const start = async () => { | 26 | const start = async () => { |
27 | await initDatabaseModels(true) | 27 | await initDatabaseModels(true) |
28 | 28 | ||
@@ -31,22 +31,39 @@ const start = async () => { | |||
31 | const initContext = (replServer) => { | 31 | const initContext = (replServer) => { |
32 | return (context) => { | 32 | return (context) => { |
33 | const properties = { | 33 | const properties = { |
34 | context, repl: replServer, env: process.env, | 34 | context, |
35 | lodash: _, path, | 35 | repl: replServer, |
36 | uuidv1, uuidv3, uuidv4, uuidv5, | 36 | env: process.env, |
37 | cli, logger, constants, | 37 | lodash: _, |
38 | Sequelize, sequelizeTypescript, modelsUtils, | 38 | path, |
39 | models: sequelizeTypescript.models, transaction: sequelizeTypescript.transaction, | 39 | uuidv1, |
40 | query: sequelizeTypescript.query, queryInterface: sequelizeTypescript.getQueryInterface(), | 40 | uuidv3, |
41 | uuidv4, | ||
42 | uuidv5, | ||
43 | cli, | ||
44 | logger, | ||
45 | constants, | ||
46 | Sequelize, | ||
47 | sequelizeTypescript, | ||
48 | modelsUtils, | ||
49 | models: sequelizeTypescript.models, | ||
50 | transaction: sequelizeTypescript.transaction, | ||
51 | query: sequelizeTypescript.query, | ||
52 | queryInterface: sequelizeTypescript.getQueryInterface(), | ||
41 | YoutubeDL, | 53 | YoutubeDL, |
42 | coreUtils, ffmpegUtils, peertubeCryptoUtils, signupUtils, utils, YoutubeDLUtils | 54 | coreUtils, |
55 | ffmpegUtils, | ||
56 | peertubeCryptoUtils, | ||
57 | signupUtils, | ||
58 | utils, | ||
59 | YoutubeDLUtils | ||
43 | } | 60 | } |
44 | 61 | ||
45 | for (let prop in properties) { | 62 | for (const prop in properties) { |
46 | Object.defineProperty(context, prop, { | 63 | Object.defineProperty(context, prop, { |
47 | configurable: false, | 64 | configurable: false, |
48 | enumerable: true, | 65 | enumerable: true, |
49 | value: properties[ prop ] | 66 | value: properties[prop] |
50 | }) | 67 | }) |
51 | } | 68 | } |
52 | } | 69 | } |
diff --git a/server/tools/peertube-upload.ts b/server/tools/peertube-upload.ts index f604c9bee..8de952e7b 100644 --- a/server/tools/peertube-upload.ts +++ b/server/tools/peertube-upload.ts | |||
@@ -24,14 +24,14 @@ command | |||
24 | 24 | ||
25 | getServerCredentials(command) | 25 | getServerCredentials(command) |
26 | .then(({ url, username, password }) => { | 26 | .then(({ url, username, password }) => { |
27 | if (!program[ 'videoName' ] || !program[ 'file' ]) { | 27 | if (!program['videoName'] || !program['file']) { |
28 | if (!program[ 'videoName' ]) console.error('--video-name is required.') | 28 | if (!program['videoName']) console.error('--video-name is required.') |
29 | if (!program[ 'file' ]) console.error('--file is required.') | 29 | if (!program['file']) console.error('--file is required.') |
30 | 30 | ||
31 | process.exit(-1) | 31 | process.exit(-1) |
32 | } | 32 | } |
33 | 33 | ||
34 | if (isAbsolute(program[ 'file' ]) === false) { | 34 | if (isAbsolute(program['file']) === false) { |
35 | console.error('File path should be absolute.') | 35 | console.error('File path should be absolute.') |
36 | process.exit(-1) | 36 | process.exit(-1) |
37 | } | 37 | } |
@@ -41,25 +41,26 @@ getServerCredentials(command) | |||
41 | process.exit(-1) | 41 | process.exit(-1) |
42 | }) | 42 | }) |
43 | }) | 43 | }) |
44 | .catch(err => console.error(err)) | ||
44 | 45 | ||
45 | async function run (url: string, username: string, password: string) { | 46 | async function run (url: string, username: string, password: string) { |
46 | const accessToken = await getAccessToken(url, username, password) | 47 | const accessToken = await getAccessToken(url, username, password) |
47 | 48 | ||
48 | await access(program[ 'file' ], constants.F_OK) | 49 | await access(program['file'], constants.F_OK) |
49 | 50 | ||
50 | console.log('Uploading %s video...', program[ 'videoName' ]) | 51 | console.log('Uploading %s video...', program['videoName']) |
51 | 52 | ||
52 | const videoAttributes = await buildVideoAttributesFromCommander(url, program) | 53 | const videoAttributes = await buildVideoAttributesFromCommander(url, program) |
53 | 54 | ||
54 | Object.assign(videoAttributes, { | 55 | Object.assign(videoAttributes, { |
55 | fixture: program[ 'file' ], | 56 | fixture: program['file'], |
56 | thumbnailfile: program[ 'thumbnail' ], | 57 | thumbnailfile: program['thumbnail'], |
57 | previewfile: program[ 'preview' ] | 58 | previewfile: program['preview'] |
58 | }) | 59 | }) |
59 | 60 | ||
60 | try { | 61 | try { |
61 | await uploadVideo(url, accessToken, videoAttributes) | 62 | await uploadVideo(url, accessToken, videoAttributes) |
62 | console.log(`Video ${program[ 'videoName' ]} uploaded.`) | 63 | console.log(`Video ${program['videoName']} uploaded.`) |
63 | process.exit(0) | 64 | process.exit(0) |
64 | } catch (err) { | 65 | } catch (err) { |
65 | console.error(require('util').inspect(err)) | 66 | console.error(require('util').inspect(err)) |
diff --git a/server/tools/peertube-watch.ts b/server/tools/peertube-watch.ts index 9ac1d05f9..5f7d1bb07 100644 --- a/server/tools/peertube-watch.ts +++ b/server/tools/peertube-watch.ts | |||
@@ -29,16 +29,10 @@ program | |||
29 | console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10') | 29 | console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10') |
30 | console.log() | 30 | console.log() |
31 | }) | 31 | }) |
32 | .action((url, cmd) => { | 32 | .action((url, cmd) => run(url, cmd)) |
33 | run(url, cmd) | ||
34 | .catch(err => { | ||
35 | console.error(err) | ||
36 | process.exit(-1) | ||
37 | }) | ||
38 | }) | ||
39 | .parse(process.argv) | 33 | .parse(process.argv) |
40 | 34 | ||
41 | async function run (url: string, program: any) { | 35 | function run (url: string, program: any) { |
42 | if (!url) { | 36 | if (!url) { |
43 | console.error('<url> positional argument is required.') | 37 | console.error('<url> positional argument is required.') |
44 | process.exit(-1) | 38 | process.exit(-1) |
diff --git a/server/tools/peertube.ts b/server/tools/peertube.ts index fc85c4210..88dd5f7f6 100644 --- a/server/tools/peertube.ts +++ b/server/tools/peertube.ts | |||
@@ -1,13 +1,12 @@ | |||
1 | #!/usr/bin/env node | 1 | #!/usr/bin/env node |
2 | 2 | ||
3 | /* eslint-disable no-useless-escape */ | ||
4 | |||
3 | import { registerTSPaths } from '../helpers/register-ts-paths' | 5 | import { registerTSPaths } from '../helpers/register-ts-paths' |
4 | registerTSPaths() | 6 | registerTSPaths() |
5 | 7 | ||
6 | import * as program from 'commander' | 8 | import * as program from 'commander' |
7 | import { | 9 | import { getSettings, version } from './cli' |
8 | version, | ||
9 | getSettings | ||
10 | } from './cli' | ||
11 | 10 | ||
12 | program | 11 | program |
13 | .version(version, '-v, --version') | 12 | .version(version, '-v, --version') |
@@ -22,17 +21,19 @@ program | |||
22 | .command('watch', 'watch a video in the terminal ✩°。⋆').alias('w') | 21 | .command('watch', 'watch a video in the terminal ✩°。⋆').alias('w') |
23 | .command('repl', 'initiate a REPL to access internals') | 22 | .command('repl', 'initiate a REPL to access internals') |
24 | .command('plugins [action]', 'manage instance plugins/themes').alias('p') | 23 | .command('plugins [action]', 'manage instance plugins/themes').alias('p') |
24 | .command('redundancy [action]', 'manage instance redundancies').alias('r') | ||
25 | 25 | ||
26 | /* Not Yet Implemented */ | 26 | /* Not Yet Implemented */ |
27 | program | 27 | program |
28 | .command('diagnostic [action]', | 28 | .command( |
29 | 'like couple therapy, but for your instance', | 29 | 'diagnostic [action]', |
30 | { noHelp: true } as program.CommandOptions | 30 | 'like couple therapy, but for your instance', |
31 | ).alias('d') | 31 | { noHelp: true } as program.CommandOptions |
32 | ).alias('d') | ||
32 | .command('admin', | 33 | .command('admin', |
33 | 'manage an instance where you have elevated rights', | 34 | 'manage an instance where you have elevated rights', |
34 | { noHelp: true } as program.CommandOptions | 35 | { noHelp: true } as program.CommandOptions |
35 | ).alias('a') | 36 | ).alias('a') |
36 | 37 | ||
37 | // help on no command | 38 | // help on no command |
38 | if (!process.argv.slice(2).length) { | 39 | if (!process.argv.slice(2).length) { |
@@ -81,3 +82,4 @@ getSettings() | |||
81 | }) | 82 | }) |
82 | .parse(process.argv) | 83 | .parse(process.argv) |
83 | }) | 84 | }) |
85 | .catch(err => console.error(err)) | ||
diff --git a/server/tools/yarn.lock b/server/tools/yarn.lock index 28756cbc2..ccd716a51 100644 --- a/server/tools/yarn.lock +++ b/server/tools/yarn.lock | |||
@@ -347,12 +347,15 @@ chunk-store-stream@^4.0.0: | |||
347 | block-stream2 "^2.0.0" | 347 | block-stream2 "^2.0.0" |
348 | readable-stream "^3.4.0" | 348 | readable-stream "^3.4.0" |
349 | 349 | ||
350 | cli-table@^0.3.1: | 350 | cli-table3@^0.5.1: |
351 | version "0.3.1" | 351 | version "0.5.1" |
352 | resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" | 352 | resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" |
353 | integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= | 353 | integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== |
354 | dependencies: | 354 | dependencies: |
355 | colors "1.0.3" | 355 | object-assign "^4.1.0" |
356 | string-width "^2.1.1" | ||
357 | optionalDependencies: | ||
358 | colors "^1.1.2" | ||
356 | 359 | ||
357 | clivas@^0.2.0: | 360 | clivas@^0.2.0: |
358 | version "0.2.0" | 361 | version "0.2.0" |
@@ -364,10 +367,10 @@ code-point-at@^1.0.0: | |||
364 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" | 367 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" |
365 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= | 368 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= |
366 | 369 | ||
367 | colors@1.0.3: | 370 | colors@^1.1.2: |
368 | version "1.0.3" | 371 | version "1.4.0" |
369 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" | 372 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" |
370 | integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= | 373 | integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== |
371 | 374 | ||
372 | common-tags@^1.8.0: | 375 | common-tags@^1.8.0: |
373 | version "1.8.0" | 376 | version "1.8.0" |
@@ -1609,7 +1612,7 @@ string-width@^1.0.1: | |||
1609 | is-fullwidth-code-point "^1.0.0" | 1612 | is-fullwidth-code-point "^1.0.0" |
1610 | strip-ansi "^3.0.0" | 1613 | strip-ansi "^3.0.0" |
1611 | 1614 | ||
1612 | "string-width@^1.0.2 || 2": | 1615 | "string-width@^1.0.2 || 2", string-width@^2.1.1: |
1613 | version "2.1.1" | 1616 | version "2.1.1" |
1614 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" | 1617 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" |
1615 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== | 1618 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== |
diff --git a/server/typings/express.ts b/server/typings/express.ts index 3cc7c7632..43a9b2c99 100644 --- a/server/typings/express.ts +++ b/server/typings/express.ts | |||
@@ -21,7 +21,7 @@ import { | |||
21 | } from './models' | 21 | } from './models' |
22 | import { MVideoPlaylistFull, MVideoPlaylistFullSummary } from './models/video/video-playlist' | 22 | import { MVideoPlaylistFull, MVideoPlaylistFullSummary } from './models/video/video-playlist' |
23 | import { MVideoImportDefault } from '@server/typings/models/video/video-import' | 23 | import { MVideoImportDefault } from '@server/typings/models/video/video-import' |
24 | import { MAccountBlocklist, MStreamingPlaylist, MVideoFile } from '@server/typings/models' | 24 | import { MAccountBlocklist, MActorUrl, MStreamingPlaylist, MVideoFile } from '@server/typings/models' |
25 | import { MVideoPlaylistElement, MVideoPlaylistElementVideoUrlPlaylistPrivacy } from '@server/typings/models/video/video-playlist-element' | 25 | import { MVideoPlaylistElement, MVideoPlaylistElementVideoUrlPlaylistPrivacy } from '@server/typings/models/video/video-playlist-element' |
26 | import { MAccountVideoRateAccountVideo } from '@server/typings/models/video/video-rate' | 26 | import { MAccountVideoRateAccountVideo } from '@server/typings/models/video/video-rate' |
27 | import { MVideoChangeOwnershipFull } from './models/video/video-change-ownership' | 27 | import { MVideoChangeOwnershipFull } from './models/video/video-change-ownership' |
@@ -74,6 +74,7 @@ declare module 'express' { | |||
74 | 74 | ||
75 | account?: MAccountDefault | 75 | account?: MAccountDefault |
76 | 76 | ||
77 | actorUrl?: MActorUrl | ||
77 | actorFull?: MActorFull | 78 | actorFull?: MActorFull |
78 | 79 | ||
79 | user?: MUserDefault | 80 | user?: MUserDefault |
diff --git a/server/typings/models/account/account-blocklist.ts b/server/typings/models/account/account-blocklist.ts index c9cb55332..0d8bf11bd 100644 --- a/server/typings/models/account/account-blocklist.ts +++ b/server/typings/models/account/account-blocklist.ts | |||
@@ -12,7 +12,8 @@ export type MAccountBlocklist = Omit<AccountBlocklistModel, 'ByAccount' | 'Block | |||
12 | 12 | ||
13 | export type MAccountBlocklistId = Pick<AccountBlocklistModel, 'id'> | 13 | export type MAccountBlocklistId = Pick<AccountBlocklistModel, 'id'> |
14 | 14 | ||
15 | export type MAccountBlocklistAccounts = MAccountBlocklist & | 15 | export type MAccountBlocklistAccounts = |
16 | MAccountBlocklist & | ||
16 | Use<'ByAccount', MAccountDefault> & | 17 | Use<'ByAccount', MAccountDefault> & |
17 | Use<'BlockedAccount', MAccountDefault> | 18 | Use<'BlockedAccount', MAccountDefault> |
18 | 19 | ||
@@ -20,6 +21,7 @@ export type MAccountBlocklistAccounts = MAccountBlocklist & | |||
20 | 21 | ||
21 | // Format for API or AP object | 22 | // Format for API or AP object |
22 | 23 | ||
23 | export type MAccountBlocklistFormattable = Pick<MAccountBlocklist, 'createdAt'> & | 24 | export type MAccountBlocklistFormattable = |
25 | Pick<MAccountBlocklist, 'createdAt'> & | ||
24 | Use<'ByAccount', MAccountFormattable> & | 26 | Use<'ByAccount', MAccountFormattable> & |
25 | Use<'BlockedAccount', MAccountFormattable> | 27 | Use<'BlockedAccount', MAccountFormattable> |
diff --git a/server/typings/models/account/account.ts b/server/typings/models/account/account.ts index adb1f3689..7b826ee04 100644 --- a/server/typings/models/account/account.ts +++ b/server/typings/models/account/account.ts | |||
@@ -21,7 +21,8 @@ type Use<K extends keyof AccountModel, M> = PickWith<AccountModel, K, M> | |||
21 | 21 | ||
22 | // ############################################################################ | 22 | // ############################################################################ |
23 | 23 | ||
24 | export type MAccount = Omit<AccountModel, 'Actor' | 'User' | 'Application' | 'VideoChannels' | 'VideoPlaylists' | | 24 | export type MAccount = |
25 | Omit<AccountModel, 'Actor' | 'User' | 'Application' | 'VideoChannels' | 'VideoPlaylists' | | ||
25 | 'VideoComments' | 'BlockedAccounts'> | 26 | 'VideoComments' | 'BlockedAccounts'> |
26 | 27 | ||
27 | // ############################################################################ | 28 | // ############################################################################ |
@@ -34,62 +35,75 @@ export type MAccountUserId = Pick<MAccount, 'userId'> | |||
34 | export type MAccountUrl = Use<'Actor', MActorUrl> | 35 | export type MAccountUrl = Use<'Actor', MActorUrl> |
35 | export type MAccountAudience = Use<'Actor', MActorAudience> | 36 | export type MAccountAudience = Use<'Actor', MActorAudience> |
36 | 37 | ||
37 | export type MAccountIdActor = MAccountId & | 38 | export type MAccountIdActor = |
39 | MAccountId & | ||
38 | Use<'Actor', MActor> | 40 | Use<'Actor', MActor> |
39 | 41 | ||
40 | export type MAccountIdActorId = MAccountId & | 42 | export type MAccountIdActorId = |
43 | MAccountId & | ||
41 | Use<'Actor', MActorId> | 44 | Use<'Actor', MActorId> |
42 | 45 | ||
43 | // ############################################################################ | 46 | // ############################################################################ |
44 | 47 | ||
45 | // Default scope | 48 | // Default scope |
46 | export type MAccountDefault = MAccount & | 49 | export type MAccountDefault = |
50 | MAccount & | ||
47 | Use<'Actor', MActorDefault> | 51 | Use<'Actor', MActorDefault> |
48 | 52 | ||
49 | // Default with default association scopes | 53 | // Default with default association scopes |
50 | export type MAccountDefaultChannelDefault = MAccount & | 54 | export type MAccountDefaultChannelDefault = |
55 | MAccount & | ||
51 | Use<'Actor', MActorDefault> & | 56 | Use<'Actor', MActorDefault> & |
52 | Use<'VideoChannels', MChannelDefault[]> | 57 | Use<'VideoChannels', MChannelDefault[]> |
53 | 58 | ||
54 | // We don't need some actors attributes | 59 | // We don't need some actors attributes |
55 | export type MAccountLight = MAccount & | 60 | export type MAccountLight = |
61 | MAccount & | ||
56 | Use<'Actor', MActorDefaultLight> | 62 | Use<'Actor', MActorDefaultLight> |
57 | 63 | ||
58 | // ############################################################################ | 64 | // ############################################################################ |
59 | 65 | ||
60 | // Full actor | 66 | // Full actor |
61 | export type MAccountActor = MAccount & | 67 | export type MAccountActor = |
68 | MAccount & | ||
62 | Use<'Actor', MActor> | 69 | Use<'Actor', MActor> |
63 | 70 | ||
64 | // Full actor with server | 71 | // Full actor with server |
65 | export type MAccountServer = MAccount & | 72 | export type MAccountServer = |
73 | MAccount & | ||
66 | Use<'Actor', MActorServer> | 74 | Use<'Actor', MActorServer> |
67 | 75 | ||
68 | // ############################################################################ | 76 | // ############################################################################ |
69 | 77 | ||
70 | // For API | 78 | // For API |
71 | 79 | ||
72 | export type MAccountSummary = FunctionProperties<MAccount> & | 80 | export type MAccountSummary = |
81 | FunctionProperties<MAccount> & | ||
73 | Pick<MAccount, 'id' | 'name'> & | 82 | Pick<MAccount, 'id' | 'name'> & |
74 | Use<'Actor', MActorSummary> | 83 | Use<'Actor', MActorSummary> |
75 | 84 | ||
76 | export type MAccountSummaryBlocks = MAccountSummary & | 85 | export type MAccountSummaryBlocks = |
86 | MAccountSummary & | ||
77 | Use<'BlockedAccounts', MAccountBlocklistId[]> | 87 | Use<'BlockedAccounts', MAccountBlocklistId[]> |
78 | 88 | ||
79 | export type MAccountAPI = MAccount & | 89 | export type MAccountAPI = |
90 | MAccount & | ||
80 | Use<'Actor', MActorAPI> | 91 | Use<'Actor', MActorAPI> |
81 | 92 | ||
82 | // ############################################################################ | 93 | // ############################################################################ |
83 | 94 | ||
84 | // Format for API or AP object | 95 | // Format for API or AP object |
85 | 96 | ||
86 | export type MAccountSummaryFormattable = FunctionProperties<MAccount> & | 97 | export type MAccountSummaryFormattable = |
98 | FunctionProperties<MAccount> & | ||
87 | Pick<MAccount, 'id' | 'name'> & | 99 | Pick<MAccount, 'id' | 'name'> & |
88 | Use<'Actor', MActorSummaryFormattable> | 100 | Use<'Actor', MActorSummaryFormattable> |
89 | 101 | ||
90 | export type MAccountFormattable = FunctionProperties<MAccount> & | 102 | export type MAccountFormattable = |
103 | FunctionProperties<MAccount> & | ||
91 | Pick<MAccount, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'userId'> & | 104 | Pick<MAccount, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'userId'> & |
92 | Use<'Actor', MActorFormattable> | 105 | Use<'Actor', MActorFormattable> |
93 | 106 | ||
94 | export type MAccountAP = Pick<MAccount, 'name' | 'description'> & | 107 | export type MAccountAP = |
108 | Pick<MAccount, 'name' | 'description'> & | ||
95 | Use<'Actor', MActorAP> | 109 | Use<'Actor', MActorAP> |
diff --git a/server/typings/models/account/actor-follow.ts b/server/typings/models/account/actor-follow.ts index f44157eba..5d0c03c8d 100644 --- a/server/typings/models/account/actor-follow.ts +++ b/server/typings/models/account/actor-follow.ts | |||
@@ -20,22 +20,26 @@ export type MActorFollow = Omit<ActorFollowModel, 'ActorFollower' | 'ActorFollow | |||
20 | 20 | ||
21 | // ############################################################################ | 21 | // ############################################################################ |
22 | 22 | ||
23 | export type MActorFollowFollowingHost = MActorFollow & | 23 | export type MActorFollowFollowingHost = |
24 | MActorFollow & | ||
24 | Use<'ActorFollowing', MActorUsername & MActorHost> | 25 | Use<'ActorFollowing', MActorUsername & MActorHost> |
25 | 26 | ||
26 | // ############################################################################ | 27 | // ############################################################################ |
27 | 28 | ||
28 | // With actors or actors default | 29 | // With actors or actors default |
29 | 30 | ||
30 | export type MActorFollowActors = MActorFollow & | 31 | export type MActorFollowActors = |
32 | MActorFollow & | ||
31 | Use<'ActorFollower', MActor> & | 33 | Use<'ActorFollower', MActor> & |
32 | Use<'ActorFollowing', MActor> | 34 | Use<'ActorFollowing', MActor> |
33 | 35 | ||
34 | export type MActorFollowActorsDefault = MActorFollow & | 36 | export type MActorFollowActorsDefault = |
37 | MActorFollow & | ||
35 | Use<'ActorFollower', MActorDefault> & | 38 | Use<'ActorFollower', MActorDefault> & |
36 | Use<'ActorFollowing', MActorDefault> | 39 | Use<'ActorFollowing', MActorDefault> |
37 | 40 | ||
38 | export type MActorFollowFull = MActorFollow & | 41 | export type MActorFollowFull = |
42 | MActorFollow & | ||
39 | Use<'ActorFollower', MActorDefaultAccountChannel> & | 43 | Use<'ActorFollower', MActorDefaultAccountChannel> & |
40 | Use<'ActorFollowing', MActorDefaultAccountChannel> | 44 | Use<'ActorFollowing', MActorDefaultAccountChannel> |
41 | 45 | ||
@@ -43,20 +47,24 @@ export type MActorFollowFull = MActorFollow & | |||
43 | 47 | ||
44 | // For subscriptions | 48 | // For subscriptions |
45 | 49 | ||
46 | type SubscriptionFollowing = MActorDefault & | 50 | type SubscriptionFollowing = |
51 | MActorDefault & | ||
47 | PickWith<ActorModel, 'VideoChannel', MChannelDefault> | 52 | PickWith<ActorModel, 'VideoChannel', MChannelDefault> |
48 | 53 | ||
49 | export type MActorFollowActorsDefaultSubscription = MActorFollow & | 54 | export type MActorFollowActorsDefaultSubscription = |
55 | MActorFollow & | ||
50 | Use<'ActorFollower', MActorDefault> & | 56 | Use<'ActorFollower', MActorDefault> & |
51 | Use<'ActorFollowing', SubscriptionFollowing> | 57 | Use<'ActorFollowing', SubscriptionFollowing> |
52 | 58 | ||
53 | export type MActorFollowSubscriptions = MActorFollow & | 59 | export type MActorFollowSubscriptions = |
60 | MActorFollow & | ||
54 | Use<'ActorFollowing', MActorChannelAccountActor> | 61 | Use<'ActorFollowing', MActorChannelAccountActor> |
55 | 62 | ||
56 | // ############################################################################ | 63 | // ############################################################################ |
57 | 64 | ||
58 | // Format for API or AP object | 65 | // Format for API or AP object |
59 | 66 | ||
60 | export type MActorFollowFormattable = Pick<MActorFollow, 'id' | 'score' | 'state' | 'createdAt' | 'updatedAt'> & | 67 | export type MActorFollowFormattable = |
68 | Pick<MActorFollow, 'id' | 'score' | 'state' | 'createdAt' | 'updatedAt'> & | ||
61 | Use<'ActorFollower', MActorFormattable> & | 69 | Use<'ActorFollower', MActorFormattable> & |
62 | Use<'ActorFollowing', MActorFormattable> | 70 | Use<'ActorFollowing', MActorFormattable> |
diff --git a/server/typings/models/account/actor.ts b/server/typings/models/account/actor.ts index ee4ece755..1160e84cb 100644 --- a/server/typings/models/account/actor.ts +++ b/server/typings/models/account/actor.ts | |||
@@ -31,18 +31,23 @@ export type MActorLight = Omit<MActor, 'privateKey' | 'privateKey'> | |||
31 | export type MActorHost = Use<'Server', MServerHost> | 31 | export type MActorHost = Use<'Server', MServerHost> |
32 | export type MActorRedundancyAllowedOpt = PickWithOpt<ActorModel, 'Server', MServerRedundancyAllowed> | 32 | export type MActorRedundancyAllowedOpt = PickWithOpt<ActorModel, 'Server', MServerRedundancyAllowed> |
33 | 33 | ||
34 | export type MActorDefaultLight = MActorLight & | 34 | export type MActorDefaultLight = |
35 | MActorLight & | ||
35 | Use<'Server', MServerHost> & | 36 | Use<'Server', MServerHost> & |
36 | Use<'Avatar', MAvatar> | 37 | Use<'Avatar', MAvatar> |
37 | 38 | ||
38 | export type MActorAccountId = MActor & | 39 | export type MActorAccountId = |
40 | MActor & | ||
39 | Use<'Account', MAccountId> | 41 | Use<'Account', MAccountId> |
40 | export type MActorAccountIdActor = MActor & | 42 | export type MActorAccountIdActor = |
43 | MActor & | ||
41 | Use<'Account', MAccountIdActor> | 44 | Use<'Account', MAccountIdActor> |
42 | 45 | ||
43 | export type MActorChannelId = MActor & | 46 | export type MActorChannelId = |
47 | MActor & | ||
44 | Use<'VideoChannel', MChannelId> | 48 | Use<'VideoChannel', MChannelId> |
45 | export type MActorChannelIdActor = MActor & | 49 | export type MActorChannelIdActor = |
50 | MActor & | ||
46 | Use<'VideoChannel', MChannelIdActor> | 51 | Use<'VideoChannel', MChannelIdActor> |
47 | 52 | ||
48 | export type MActorAccountChannelId = MActorAccountId & MActorChannelId | 53 | export type MActorAccountChannelId = MActorAccountId & MActorChannelId |
@@ -52,38 +57,45 @@ export type MActorAccountChannelIdActor = MActorAccountIdActor & MActorChannelId | |||
52 | 57 | ||
53 | // Include raw account/channel/server | 58 | // Include raw account/channel/server |
54 | 59 | ||
55 | export type MActorAccount = MActor & | 60 | export type MActorAccount = |
61 | MActor & | ||
56 | Use<'Account', MAccount> | 62 | Use<'Account', MAccount> |
57 | 63 | ||
58 | export type MActorChannel = MActor & | 64 | export type MActorChannel = |
65 | MActor & | ||
59 | Use<'VideoChannel', MChannel> | 66 | Use<'VideoChannel', MChannel> |
60 | 67 | ||
61 | export type MActorDefaultAccountChannel = MActorDefault & MActorAccount & MActorChannel | 68 | export type MActorDefaultAccountChannel = MActorDefault & MActorAccount & MActorChannel |
62 | 69 | ||
63 | export type MActorServer = MActor & | 70 | export type MActorServer = |
71 | MActor & | ||
64 | Use<'Server', MServer> | 72 | Use<'Server', MServer> |
65 | 73 | ||
66 | // ############################################################################ | 74 | // ############################################################################ |
67 | 75 | ||
68 | // Complex actor associations | 76 | // Complex actor associations |
69 | 77 | ||
70 | export type MActorDefault = MActor & | 78 | export type MActorDefault = |
79 | MActor & | ||
71 | Use<'Server', MServer> & | 80 | Use<'Server', MServer> & |
72 | Use<'Avatar', MAvatar> | 81 | Use<'Avatar', MAvatar> |
73 | 82 | ||
74 | // Actor with channel that is associated to an account and its actor | 83 | // Actor with channel that is associated to an account and its actor |
75 | // Actor -> VideoChannel -> Account -> Actor | 84 | // Actor -> VideoChannel -> Account -> Actor |
76 | export type MActorChannelAccountActor = MActor & | 85 | export type MActorChannelAccountActor = |
86 | MActor & | ||
77 | Use<'VideoChannel', MChannelAccountActor> | 87 | Use<'VideoChannel', MChannelAccountActor> |
78 | 88 | ||
79 | export type MActorFull = MActor & | 89 | export type MActorFull = |
90 | MActor & | ||
80 | Use<'Server', MServer> & | 91 | Use<'Server', MServer> & |
81 | Use<'Avatar', MAvatar> & | 92 | Use<'Avatar', MAvatar> & |
82 | Use<'Account', MAccount> & | 93 | Use<'Account', MAccount> & |
83 | Use<'VideoChannel', MChannelAccountActor> | 94 | Use<'VideoChannel', MChannelAccountActor> |
84 | 95 | ||
85 | // Same than ActorFull, but the account and the channel have their actor | 96 | // Same than ActorFull, but the account and the channel have their actor |
86 | export type MActorFullActor = MActor & | 97 | export type MActorFullActor = |
98 | MActor & | ||
87 | Use<'Server', MServer> & | 99 | Use<'Server', MServer> & |
88 | Use<'Avatar', MAvatar> & | 100 | Use<'Avatar', MAvatar> & |
89 | Use<'Account', MAccountDefault> & | 101 | Use<'Account', MAccountDefault> & |
@@ -93,29 +105,35 @@ export type MActorFullActor = MActor & | |||
93 | 105 | ||
94 | // API | 106 | // API |
95 | 107 | ||
96 | export type MActorSummary = FunctionProperties<MActor> & | 108 | export type MActorSummary = |
109 | FunctionProperties<MActor> & | ||
97 | Pick<MActor, 'id' | 'preferredUsername' | 'url' | 'serverId' | 'avatarId'> & | 110 | Pick<MActor, 'id' | 'preferredUsername' | 'url' | 'serverId' | 'avatarId'> & |
98 | Use<'Server', MServerHost> & | 111 | Use<'Server', MServerHost> & |
99 | Use<'Avatar', MAvatar> | 112 | Use<'Avatar', MAvatar> |
100 | 113 | ||
101 | export type MActorSummaryBlocks = MActorSummary & | 114 | export type MActorSummaryBlocks = |
115 | MActorSummary & | ||
102 | Use<'Server', MServerHostBlocks> | 116 | Use<'Server', MServerHostBlocks> |
103 | 117 | ||
104 | export type MActorAPI = Omit<MActorDefault, 'publicKey' | 'privateKey' | 'inboxUrl' | 'outboxUrl' | 'sharedInboxUrl' | | 118 | export type MActorAPI = |
119 | Omit<MActorDefault, 'publicKey' | 'privateKey' | 'inboxUrl' | 'outboxUrl' | 'sharedInboxUrl' | | ||
105 | 'followersUrl' | 'followingUrl' | 'url' | 'createdAt' | 'updatedAt'> | 120 | 'followersUrl' | 'followingUrl' | 'url' | 'createdAt' | 'updatedAt'> |
106 | 121 | ||
107 | // ############################################################################ | 122 | // ############################################################################ |
108 | 123 | ||
109 | // Format for API or AP object | 124 | // Format for API or AP object |
110 | 125 | ||
111 | export type MActorSummaryFormattable = FunctionProperties<MActor> & | 126 | export type MActorSummaryFormattable = |
127 | FunctionProperties<MActor> & | ||
112 | Pick<MActor, 'url' | 'preferredUsername'> & | 128 | Pick<MActor, 'url' | 'preferredUsername'> & |
113 | Use<'Server', MServerHost> & | 129 | Use<'Server', MServerHost> & |
114 | Use<'Avatar', MAvatarFormattable> | 130 | Use<'Avatar', MAvatarFormattable> |
115 | 131 | ||
116 | export type MActorFormattable = MActorSummaryFormattable & | 132 | export type MActorFormattable = |
133 | MActorSummaryFormattable & | ||
117 | Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt'> & | 134 | Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt'> & |
118 | Use<'Server', MServerHost & Partial<Pick<MServer, 'redundancyAllowed'>>> | 135 | Use<'Server', MServerHost & Partial<Pick<MServer, 'redundancyAllowed'>>> |
119 | 136 | ||
120 | export type MActorAP = MActor & | 137 | export type MActorAP = |
138 | MActor & | ||
121 | Use<'Avatar', MAvatar> | 139 | Use<'Avatar', MAvatar> |
diff --git a/server/typings/models/account/avatar.ts b/server/typings/models/account/avatar.ts index 8af6cc787..21b47180f 100644 --- a/server/typings/models/account/avatar.ts +++ b/server/typings/models/account/avatar.ts | |||
@@ -7,5 +7,6 @@ export type MAvatar = AvatarModel | |||
7 | 7 | ||
8 | // Format for API or AP object | 8 | // Format for API or AP object |
9 | 9 | ||
10 | export type MAvatarFormattable = FunctionProperties<MAvatar> & | 10 | export type MAvatarFormattable = |
11 | FunctionProperties<MAvatar> & | ||
11 | Pick<MAvatar, 'filename' | 'createdAt' | 'updatedAt'> | 12 | Pick<MAvatar, 'filename' | 'createdAt' | 'updatedAt'> |
diff --git a/server/typings/models/oauth/oauth-token.ts b/server/typings/models/oauth/oauth-token.ts index 8ef042d4e..b24a95fd8 100644 --- a/server/typings/models/oauth/oauth-token.ts +++ b/server/typings/models/oauth/oauth-token.ts | |||
@@ -8,6 +8,7 @@ type Use<K extends keyof OAuthTokenModel, M> = PickWith<OAuthTokenModel, K, M> | |||
8 | 8 | ||
9 | export type MOAuthToken = Omit<OAuthTokenModel, 'User' | 'OAuthClients'> | 9 | export type MOAuthToken = Omit<OAuthTokenModel, 'User' | 'OAuthClients'> |
10 | 10 | ||
11 | export type MOAuthTokenUser = MOAuthToken & | 11 | export type MOAuthTokenUser = |
12 | MOAuthToken & | ||
12 | Use<'User', MUserAccountUrl> & | 13 | Use<'User', MUserAccountUrl> & |
13 | { user?: MUserAccountUrl } | 14 | { user?: MUserAccountUrl } |
diff --git a/server/typings/models/server/plugin.ts b/server/typings/models/server/plugin.ts index 94674c318..83eb83794 100644 --- a/server/typings/models/server/plugin.ts +++ b/server/typings/models/server/plugin.ts | |||
@@ -6,5 +6,6 @@ export type MPlugin = PluginModel | |||
6 | 6 | ||
7 | // Format for API or AP object | 7 | // Format for API or AP object |
8 | 8 | ||
9 | export type MPluginFormattable = Pick<MPlugin, 'name' | 'type' | 'version' | 'latestVersion' | 'enabled' | 'uninstalled' | 9 | export type MPluginFormattable = |
10 | Pick<MPlugin, 'name' | 'type' | 'version' | 'latestVersion' | 'enabled' | 'uninstalled' | ||
10 | | 'peertubeEngine' | 'description' | 'homepage' | 'settings' | 'createdAt' | 'updatedAt'> | 11 | | 'peertubeEngine' | 'description' | 'homepage' | 'settings' | 'createdAt' | 'updatedAt'> |
diff --git a/server/typings/models/server/server-blocklist.ts b/server/typings/models/server/server-blocklist.ts index c3e6230f2..ff6f49176 100644 --- a/server/typings/models/server/server-blocklist.ts +++ b/server/typings/models/server/server-blocklist.ts | |||
@@ -11,7 +11,8 @@ export type MServerBlocklist = Omit<ServerBlocklistModel, 'ByAccount' | 'Blocked | |||
11 | 11 | ||
12 | // ############################################################################ | 12 | // ############################################################################ |
13 | 13 | ||
14 | export type MServerBlocklistAccountServer = MServerBlocklist & | 14 | export type MServerBlocklistAccountServer = |
15 | MServerBlocklist & | ||
15 | Use<'ByAccount', MAccountDefault> & | 16 | Use<'ByAccount', MAccountDefault> & |
16 | Use<'BlockedServer', MServer> | 17 | Use<'BlockedServer', MServer> |
17 | 18 | ||
@@ -19,6 +20,7 @@ export type MServerBlocklistAccountServer = MServerBlocklist & | |||
19 | 20 | ||
20 | // Format for API or AP object | 21 | // Format for API or AP object |
21 | 22 | ||
22 | export type MServerBlocklistFormattable = Pick<MServerBlocklist, 'createdAt'> & | 23 | export type MServerBlocklistFormattable = |
24 | Pick<MServerBlocklist, 'createdAt'> & | ||
23 | Use<'ByAccount', MAccountFormattable> & | 25 | Use<'ByAccount', MAccountFormattable> & |
24 | Use<'BlockedServer', MServerFormattable> | 26 | Use<'BlockedServer', MServerFormattable> |
diff --git a/server/typings/models/server/server.ts b/server/typings/models/server/server.ts index 190cc0c28..b35e55aeb 100644 --- a/server/typings/models/server/server.ts +++ b/server/typings/models/server/server.ts | |||
@@ -13,12 +13,14 @@ export type MServer = Omit<ServerModel, 'Actors' | 'BlockedByAccounts'> | |||
13 | export type MServerHost = Pick<MServer, 'host'> | 13 | export type MServerHost = Pick<MServer, 'host'> |
14 | export type MServerRedundancyAllowed = Pick<MServer, 'redundancyAllowed'> | 14 | export type MServerRedundancyAllowed = Pick<MServer, 'redundancyAllowed'> |
15 | 15 | ||
16 | export type MServerHostBlocks = MServerHost & | 16 | export type MServerHostBlocks = |
17 | MServerHost & | ||
17 | Use<'BlockedByAccounts', MAccountBlocklistId[]> | 18 | Use<'BlockedByAccounts', MAccountBlocklistId[]> |
18 | 19 | ||
19 | // ############################################################################ | 20 | // ############################################################################ |
20 | 21 | ||
21 | // Format for API or AP object | 22 | // Format for API or AP object |
22 | 23 | ||
23 | export type MServerFormattable = FunctionProperties<MServer> & | 24 | export type MServerFormattable = |
25 | FunctionProperties<MServer> & | ||
24 | Pick<MServer, 'host'> | 26 | Pick<MServer, 'host'> |
diff --git a/server/typings/models/user/user-notification.ts b/server/typings/models/user/user-notification.ts index 1cdc691b0..2080360e1 100644 --- a/server/typings/models/user/user-notification.ts +++ b/server/typings/models/user/user-notification.ts | |||
@@ -16,59 +16,73 @@ type Use<K extends keyof UserNotificationModel, M> = PickWith<UserNotificationMo | |||
16 | 16 | ||
17 | // ############################################################################ | 17 | // ############################################################################ |
18 | 18 | ||
19 | export namespace UserNotificationIncludes { | 19 | export module UserNotificationIncludes { |
20 | |||
20 | export type VideoInclude = Pick<VideoModel, 'id' | 'uuid' | 'name'> | 21 | export type VideoInclude = Pick<VideoModel, 'id' | 'uuid' | 'name'> |
21 | export type VideoIncludeChannel = VideoInclude & | 22 | export type VideoIncludeChannel = |
23 | VideoInclude & | ||
22 | PickWith<VideoModel, 'VideoChannel', VideoChannelIncludeActor> | 24 | PickWith<VideoModel, 'VideoChannel', VideoChannelIncludeActor> |
23 | 25 | ||
24 | export type ActorInclude = Pick<ActorModel, 'preferredUsername' | 'getHost'> & | 26 | export type ActorInclude = |
27 | Pick<ActorModel, 'preferredUsername' | 'getHost'> & | ||
25 | PickWith<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> & | 28 | PickWith<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> & |
26 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> | 29 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> |
27 | 30 | ||
28 | export type VideoChannelInclude = Pick<VideoChannelModel, 'id' | 'name' | 'getDisplayName'> | 31 | export type VideoChannelInclude = Pick<VideoChannelModel, 'id' | 'name' | 'getDisplayName'> |
29 | export type VideoChannelIncludeActor = VideoChannelInclude & | 32 | export type VideoChannelIncludeActor = |
33 | VideoChannelInclude & | ||
30 | PickWith<VideoChannelModel, 'Actor', ActorInclude> | 34 | PickWith<VideoChannelModel, 'Actor', ActorInclude> |
31 | 35 | ||
32 | export type AccountInclude = Pick<AccountModel, 'id' | 'name' | 'getDisplayName'> | 36 | export type AccountInclude = Pick<AccountModel, 'id' | 'name' | 'getDisplayName'> |
33 | export type AccountIncludeActor = AccountInclude & | 37 | export type AccountIncludeActor = |
38 | AccountInclude & | ||
34 | PickWith<AccountModel, 'Actor', ActorInclude> | 39 | PickWith<AccountModel, 'Actor', ActorInclude> |
35 | 40 | ||
36 | export type VideoCommentInclude = Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> & | 41 | export type VideoCommentInclude = |
42 | Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> & | ||
37 | PickWith<VideoCommentModel, 'Account', AccountIncludeActor> & | 43 | PickWith<VideoCommentModel, 'Account', AccountIncludeActor> & |
38 | PickWith<VideoCommentModel, 'Video', VideoInclude> | 44 | PickWith<VideoCommentModel, 'Video', VideoInclude> |
39 | 45 | ||
40 | export type VideoAbuseInclude = Pick<VideoAbuseModel, 'id'> & | 46 | export type VideoAbuseInclude = |
47 | Pick<VideoAbuseModel, 'id'> & | ||
41 | PickWith<VideoAbuseModel, 'Video', VideoInclude> | 48 | PickWith<VideoAbuseModel, 'Video', VideoInclude> |
42 | 49 | ||
43 | export type VideoBlacklistInclude = Pick<VideoBlacklistModel, 'id'> & | 50 | export type VideoBlacklistInclude = |
51 | Pick<VideoBlacklistModel, 'id'> & | ||
44 | PickWith<VideoAbuseModel, 'Video', VideoInclude> | 52 | PickWith<VideoAbuseModel, 'Video', VideoInclude> |
45 | 53 | ||
46 | export type VideoImportInclude = Pick<VideoImportModel, 'id' | 'magnetUri' | 'targetUrl' | 'torrentName'> & | 54 | export type VideoImportInclude = |
55 | Pick<VideoImportModel, 'id' | 'magnetUri' | 'targetUrl' | 'torrentName'> & | ||
47 | PickWith<VideoImportModel, 'Video', VideoInclude> | 56 | PickWith<VideoImportModel, 'Video', VideoInclude> |
48 | 57 | ||
49 | export type ActorFollower = Pick<ActorModel, 'preferredUsername' | 'getHost'> & | 58 | export type ActorFollower = |
59 | Pick<ActorModel, 'preferredUsername' | 'getHost'> & | ||
50 | PickWith<ActorModel, 'Account', AccountInclude> & | 60 | PickWith<ActorModel, 'Account', AccountInclude> & |
51 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> & | 61 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> & |
52 | PickWithOpt<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> | 62 | PickWithOpt<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> |
53 | 63 | ||
54 | export type ActorFollowing = Pick<ActorModel, 'preferredUsername' | 'type' | 'getHost'> & | 64 | export type ActorFollowing = |
65 | Pick<ActorModel, 'preferredUsername' | 'type' | 'getHost'> & | ||
55 | PickWith<ActorModel, 'VideoChannel', VideoChannelInclude> & | 66 | PickWith<ActorModel, 'VideoChannel', VideoChannelInclude> & |
56 | PickWith<ActorModel, 'Account', AccountInclude> & | 67 | PickWith<ActorModel, 'Account', AccountInclude> & |
57 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> | 68 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> |
58 | 69 | ||
59 | export type ActorFollowInclude = Pick<ActorFollowModel, 'id' | 'state'> & | 70 | export type ActorFollowInclude = |
71 | Pick<ActorFollowModel, 'id' | 'state'> & | ||
60 | PickWith<ActorFollowModel, 'ActorFollower', ActorFollower> & | 72 | PickWith<ActorFollowModel, 'ActorFollower', ActorFollower> & |
61 | PickWith<ActorFollowModel, 'ActorFollowing', ActorFollowing> | 73 | PickWith<ActorFollowModel, 'ActorFollowing', ActorFollowing> |
62 | } | 74 | } |
63 | 75 | ||
64 | // ############################################################################ | 76 | // ############################################################################ |
65 | 77 | ||
66 | export type MUserNotification = Omit<UserNotificationModel, 'User' | 'Video' | 'Comment' | 'VideoAbuse' | 'VideoBlacklist' | | 78 | export type MUserNotification = |
79 | Omit<UserNotificationModel, 'User' | 'Video' | 'Comment' | 'VideoAbuse' | 'VideoBlacklist' | | ||
67 | 'VideoImport' | 'Account' | 'ActorFollow'> | 80 | 'VideoImport' | 'Account' | 'ActorFollow'> |
68 | 81 | ||
69 | // ############################################################################ | 82 | // ############################################################################ |
70 | 83 | ||
71 | export type UserNotificationModelForApi = MUserNotification & | 84 | export type UserNotificationModelForApi = |
85 | MUserNotification & | ||
72 | Use<'Video', UserNotificationIncludes.VideoIncludeChannel> & | 86 | Use<'Video', UserNotificationIncludes.VideoIncludeChannel> & |
73 | Use<'Comment', UserNotificationIncludes.VideoCommentInclude> & | 87 | Use<'Comment', UserNotificationIncludes.VideoCommentInclude> & |
74 | Use<'VideoAbuse', UserNotificationIncludes.VideoAbuseInclude> & | 88 | Use<'VideoAbuse', UserNotificationIncludes.VideoAbuseInclude> & |
diff --git a/server/typings/models/user/user.ts b/server/typings/models/user/user.ts index 6ac19c20b..31cf075ef 100644 --- a/server/typings/models/user/user.ts +++ b/server/typings/models/user/user.ts | |||
@@ -29,36 +29,44 @@ export type MUserId = Pick<UserModel, 'id'> | |||
29 | 29 | ||
30 | // With account | 30 | // With account |
31 | 31 | ||
32 | export type MUserAccountId = MUser & | 32 | export type MUserAccountId = |
33 | MUser & | ||
33 | Use<'Account', MAccountId> | 34 | Use<'Account', MAccountId> |
34 | 35 | ||
35 | export type MUserAccountUrl = MUser & | 36 | export type MUserAccountUrl = |
37 | MUser & | ||
36 | Use<'Account', MAccountUrl & MAccountIdActorId> | 38 | Use<'Account', MAccountUrl & MAccountIdActorId> |
37 | 39 | ||
38 | export type MUserAccount = MUser & | 40 | export type MUserAccount = |
41 | MUser & | ||
39 | Use<'Account', MAccount> | 42 | Use<'Account', MAccount> |
40 | 43 | ||
41 | export type MUserAccountDefault = MUser & | 44 | export type MUserAccountDefault = |
45 | MUser & | ||
42 | Use<'Account', MAccountDefault> | 46 | Use<'Account', MAccountDefault> |
43 | 47 | ||
44 | // With channel | 48 | // With channel |
45 | 49 | ||
46 | export type MUserNotifSettingChannelDefault = MUser & | 50 | export type MUserNotifSettingChannelDefault = |
51 | MUser & | ||
47 | Use<'NotificationSetting', MNotificationSetting> & | 52 | Use<'NotificationSetting', MNotificationSetting> & |
48 | Use<'Account', MAccountDefaultChannelDefault> | 53 | Use<'Account', MAccountDefaultChannelDefault> |
49 | 54 | ||
50 | // With notification settings | 55 | // With notification settings |
51 | 56 | ||
52 | export type MUserWithNotificationSetting = MUser & | 57 | export type MUserWithNotificationSetting = |
58 | MUser & | ||
53 | Use<'NotificationSetting', MNotificationSetting> | 59 | Use<'NotificationSetting', MNotificationSetting> |
54 | 60 | ||
55 | export type MUserNotifSettingAccount = MUser & | 61 | export type MUserNotifSettingAccount = |
62 | MUser & | ||
56 | Use<'NotificationSetting', MNotificationSetting> & | 63 | Use<'NotificationSetting', MNotificationSetting> & |
57 | Use<'Account', MAccount> | 64 | Use<'Account', MAccount> |
58 | 65 | ||
59 | // Default scope | 66 | // Default scope |
60 | 67 | ||
61 | export type MUserDefault = MUser & | 68 | export type MUserDefault = |
69 | MUser & | ||
62 | Use<'NotificationSetting', MNotificationSetting> & | 70 | Use<'NotificationSetting', MNotificationSetting> & |
63 | Use<'Account', MAccountDefault> | 71 | Use<'Account', MAccountDefault> |
64 | 72 | ||
@@ -67,12 +75,15 @@ export type MUserDefault = MUser & | |||
67 | // Format for API or AP object | 75 | // Format for API or AP object |
68 | 76 | ||
69 | type MAccountWithChannels = MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]> | 77 | type MAccountWithChannels = MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]> |
70 | type MAccountWithChannelsAndSpecialPlaylists = MAccountWithChannels & | 78 | type MAccountWithChannelsAndSpecialPlaylists = |
79 | MAccountWithChannels & | ||
71 | PickWithOpt<AccountModel, 'VideoPlaylists', MVideoPlaylist[]> | 80 | PickWithOpt<AccountModel, 'VideoPlaylists', MVideoPlaylist[]> |
72 | 81 | ||
73 | export type MUserFormattable = MUserQuotaUsed & | 82 | export type MUserFormattable = |
83 | MUserQuotaUsed & | ||
74 | Use<'Account', MAccountWithChannels> & | 84 | Use<'Account', MAccountWithChannels> & |
75 | PickWithOpt<UserModel, 'NotificationSetting', MNotificationSettingFormattable> | 85 | PickWithOpt<UserModel, 'NotificationSetting', MNotificationSettingFormattable> |
76 | 86 | ||
77 | export type MMyUserFormattable = MUserFormattable & | 87 | export type MMyUserFormattable = |
88 | MUserFormattable & | ||
78 | Use<'Account', MAccountWithChannelsAndSpecialPlaylists> | 89 | Use<'Account', MAccountWithChannelsAndSpecialPlaylists> |
diff --git a/server/typings/models/video/schedule-video-update.ts b/server/typings/models/video/schedule-video-update.ts index e6f478cdf..95a53d139 100644 --- a/server/typings/models/video/schedule-video-update.ts +++ b/server/typings/models/video/schedule-video-update.ts | |||
@@ -10,7 +10,8 @@ export type MScheduleVideoUpdate = Omit<ScheduleVideoUpdateModel, 'Video'> | |||
10 | 10 | ||
11 | // ############################################################################ | 11 | // ############################################################################ |
12 | 12 | ||
13 | export type MScheduleVideoUpdateVideoAll = MScheduleVideoUpdate & | 13 | export type MScheduleVideoUpdateVideoAll = |
14 | MScheduleVideoUpdate & | ||
14 | Use<'Video', MVideoAPWithoutCaption & MVideoWithBlacklistLight> | 15 | Use<'Video', MVideoAPWithoutCaption & MVideoWithBlacklistLight> |
15 | 16 | ||
16 | // Format for API or AP object | 17 | // Format for API or AP object |
diff --git a/server/typings/models/video/video-abuse.ts b/server/typings/models/video/video-abuse.ts index e38c3f586..955ec4780 100644 --- a/server/typings/models/video/video-abuse.ts +++ b/server/typings/models/video/video-abuse.ts | |||
@@ -13,11 +13,13 @@ export type MVideoAbuse = Omit<VideoAbuseModel, 'Account' | 'Video' | 'toActivit | |||
13 | 13 | ||
14 | export type MVideoAbuseId = Pick<VideoAbuseModel, 'id'> | 14 | export type MVideoAbuseId = Pick<VideoAbuseModel, 'id'> |
15 | 15 | ||
16 | export type MVideoAbuseVideo = MVideoAbuse & | 16 | export type MVideoAbuseVideo = |
17 | MVideoAbuse & | ||
17 | Pick<VideoAbuseModel, 'toActivityPubObject'> & | 18 | Pick<VideoAbuseModel, 'toActivityPubObject'> & |
18 | Use<'Video', MVideo> | 19 | Use<'Video', MVideo> |
19 | 20 | ||
20 | export type MVideoAbuseAccountVideo = MVideoAbuse & | 21 | export type MVideoAbuseAccountVideo = |
22 | MVideoAbuse & | ||
21 | Pick<VideoAbuseModel, 'toActivityPubObject'> & | 23 | Pick<VideoAbuseModel, 'toActivityPubObject'> & |
22 | Use<'Video', MVideo> & | 24 | Use<'Video', MVideo> & |
23 | Use<'Account', MAccountDefault> | 25 | Use<'Account', MAccountDefault> |
@@ -26,6 +28,7 @@ export type MVideoAbuseAccountVideo = MVideoAbuse & | |||
26 | 28 | ||
27 | // Format for API or AP object | 29 | // Format for API or AP object |
28 | 30 | ||
29 | export type MVideoAbuseFormattable = MVideoAbuse & | 31 | export type MVideoAbuseFormattable = |
32 | MVideoAbuse & | ||
30 | Use<'Account', MAccountFormattable> & | 33 | Use<'Account', MAccountFormattable> & |
31 | Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'name'>> | 34 | Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'name'>> |
diff --git a/server/typings/models/video/video-blacklist.ts b/server/typings/models/video/video-blacklist.ts index 7122a9dc0..ddb4db832 100644 --- a/server/typings/models/video/video-blacklist.ts +++ b/server/typings/models/video/video-blacklist.ts | |||
@@ -13,15 +13,18 @@ export type MVideoBlacklistUnfederated = Pick<MVideoBlacklist, 'unfederated'> | |||
13 | 13 | ||
14 | // ############################################################################ | 14 | // ############################################################################ |
15 | 15 | ||
16 | export type MVideoBlacklistLightVideo = MVideoBlacklistLight & | 16 | export type MVideoBlacklistLightVideo = |
17 | MVideoBlacklistLight & | ||
17 | Use<'Video', MVideo> | 18 | Use<'Video', MVideo> |
18 | 19 | ||
19 | export type MVideoBlacklistVideo = MVideoBlacklist & | 20 | export type MVideoBlacklistVideo = |
21 | MVideoBlacklist & | ||
20 | Use<'Video', MVideo> | 22 | Use<'Video', MVideo> |
21 | 23 | ||
22 | // ############################################################################ | 24 | // ############################################################################ |
23 | 25 | ||
24 | // Format for API or AP object | 26 | // Format for API or AP object |
25 | 27 | ||
26 | export type MVideoBlacklistFormattable = MVideoBlacklist & | 28 | export type MVideoBlacklistFormattable = |
29 | MVideoBlacklist & | ||
27 | Use<'Video', MVideoFormattable> | 30 | Use<'Video', MVideoFormattable> |
diff --git a/server/typings/models/video/video-caption.ts b/server/typings/models/video/video-caption.ts index ffa56f544..e7aff6956 100644 --- a/server/typings/models/video/video-caption.ts +++ b/server/typings/models/video/video-caption.ts | |||
@@ -11,14 +11,17 @@ export type MVideoCaption = Omit<VideoCaptionModel, 'Video'> | |||
11 | // ############################################################################ | 11 | // ############################################################################ |
12 | 12 | ||
13 | export type MVideoCaptionLanguage = Pick<MVideoCaption, 'language'> | 13 | export type MVideoCaptionLanguage = Pick<MVideoCaption, 'language'> |
14 | export type MVideoCaptionLanguageUrl = Pick<MVideoCaption, 'language' | 'fileUrl' | 'getFileUrl'> | ||
14 | 15 | ||
15 | export type MVideoCaptionVideo = MVideoCaption & | 16 | export type MVideoCaptionVideo = |
17 | MVideoCaption & | ||
16 | Use<'Video', Pick<MVideo, 'id' | 'remote' | 'uuid'>> | 18 | Use<'Video', Pick<MVideo, 'id' | 'remote' | 'uuid'>> |
17 | 19 | ||
18 | // ############################################################################ | 20 | // ############################################################################ |
19 | 21 | ||
20 | // Format for API or AP object | 22 | // Format for API or AP object |
21 | 23 | ||
22 | export type MVideoCaptionFormattable = FunctionProperties<MVideoCaption> & | 24 | export type MVideoCaptionFormattable = |
25 | FunctionProperties<MVideoCaption> & | ||
23 | Pick<MVideoCaption, 'language'> & | 26 | Pick<MVideoCaption, 'language'> & |
24 | Use<'Video', MVideoUUID> | 27 | Use<'Video', MVideoUUID> |
diff --git a/server/typings/models/video/video-change-ownership.ts b/server/typings/models/video/video-change-ownership.ts index e5b5bbc1d..971dc3db5 100644 --- a/server/typings/models/video/video-change-ownership.ts +++ b/server/typings/models/video/video-change-ownership.ts | |||
@@ -9,7 +9,8 @@ type Use<K extends keyof VideoChangeOwnershipModel, M> = PickWith<VideoChangeOwn | |||
9 | 9 | ||
10 | export type MVideoChangeOwnership = Omit<VideoChangeOwnershipModel, 'Initiator' | 'NextOwner' | 'Video'> | 10 | export type MVideoChangeOwnership = Omit<VideoChangeOwnershipModel, 'Initiator' | 'NextOwner' | 'Video'> |
11 | 11 | ||
12 | export type MVideoChangeOwnershipFull = MVideoChangeOwnership & | 12 | export type MVideoChangeOwnershipFull = |
13 | MVideoChangeOwnership & | ||
13 | Use<'Initiator', MAccountDefault> & | 14 | Use<'Initiator', MAccountDefault> & |
14 | Use<'NextOwner', MAccountDefault> & | 15 | Use<'NextOwner', MAccountDefault> & |
15 | Use<'Video', MVideoWithAllFiles> | 16 | Use<'Video', MVideoWithAllFiles> |
@@ -18,7 +19,8 @@ export type MVideoChangeOwnershipFull = MVideoChangeOwnership & | |||
18 | 19 | ||
19 | // Format for API or AP object | 20 | // Format for API or AP object |
20 | 21 | ||
21 | export type MVideoChangeOwnershipFormattable = Pick<MVideoChangeOwnership, 'id' | 'status' | 'createdAt'> & | 22 | export type MVideoChangeOwnershipFormattable = |
23 | Pick<MVideoChangeOwnership, 'id' | 'status' | 'createdAt'> & | ||
22 | Use<'Initiator', MAccountFormattable> & | 24 | Use<'Initiator', MAccountFormattable> & |
23 | Use<'NextOwner', MAccountFormattable> & | 25 | Use<'NextOwner', MAccountFormattable> & |
24 | Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'url' | 'name'>> | 26 | Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'url' | 'name'>> |
diff --git a/server/typings/models/video/video-channels.ts b/server/typings/models/video/video-channels.ts index 292d0ac95..50f7c2d8a 100644 --- a/server/typings/models/video/video-channels.ts +++ b/server/typings/models/video/video-channels.ts | |||
@@ -35,32 +35,39 @@ export type MChannelId = Pick<MChannel, 'id'> | |||
35 | 35 | ||
36 | // ############################################################################ | 36 | // ############################################################################ |
37 | 37 | ||
38 | export type MChannelIdActor = MChannelId & | 38 | export type MChannelIdActor = |
39 | MChannelId & | ||
39 | Use<'Actor', MActorAccountChannelId> | 40 | Use<'Actor', MActorAccountChannelId> |
40 | 41 | ||
41 | export type MChannelUserId = Pick<MChannel, 'accountId'> & | 42 | export type MChannelUserId = |
43 | Pick<MChannel, 'accountId'> & | ||
42 | Use<'Account', MAccountUserId> | 44 | Use<'Account', MAccountUserId> |
43 | 45 | ||
44 | export type MChannelActor = MChannel & | 46 | export type MChannelActor = |
47 | MChannel & | ||
45 | Use<'Actor', MActor> | 48 | Use<'Actor', MActor> |
46 | 49 | ||
47 | export type MChannelUrl = Use<'Actor', MActorUrl> | 50 | export type MChannelUrl = Use<'Actor', MActorUrl> |
48 | 51 | ||
49 | // Default scope | 52 | // Default scope |
50 | export type MChannelDefault = MChannel & | 53 | export type MChannelDefault = |
54 | MChannel & | ||
51 | Use<'Actor', MActorDefault> | 55 | Use<'Actor', MActorDefault> |
52 | 56 | ||
53 | // ############################################################################ | 57 | // ############################################################################ |
54 | 58 | ||
55 | // Not all association attributes | 59 | // Not all association attributes |
56 | 60 | ||
57 | export type MChannelLight = MChannel & | 61 | export type MChannelLight = |
62 | MChannel & | ||
58 | Use<'Actor', MActorDefaultLight> | 63 | Use<'Actor', MActorDefaultLight> |
59 | 64 | ||
60 | export type MChannelActorLight = MChannel & | 65 | export type MChannelActorLight = |
66 | MChannel & | ||
61 | Use<'Actor', MActorLight> | 67 | Use<'Actor', MActorLight> |
62 | 68 | ||
63 | export type MChannelAccountLight = MChannel & | 69 | export type MChannelAccountLight = |
70 | MChannel & | ||
64 | Use<'Actor', MActorDefaultLight> & | 71 | Use<'Actor', MActorDefaultLight> & |
65 | Use<'Account', MAccountLight> | 72 | Use<'Account', MAccountLight> |
66 | 73 | ||
@@ -68,24 +75,29 @@ export type MChannelAccountLight = MChannel & | |||
68 | 75 | ||
69 | // Account associations | 76 | // Account associations |
70 | 77 | ||
71 | export type MChannelAccountActor = MChannel & | 78 | export type MChannelAccountActor = |
79 | MChannel & | ||
72 | Use<'Account', MAccountActor> | 80 | Use<'Account', MAccountActor> |
73 | 81 | ||
74 | export type MChannelAccountDefault = MChannel & | 82 | export type MChannelAccountDefault = |
83 | MChannel & | ||
75 | Use<'Actor', MActorDefault> & | 84 | Use<'Actor', MActorDefault> & |
76 | Use<'Account', MAccountDefault> | 85 | Use<'Account', MAccountDefault> |
77 | 86 | ||
78 | export type MChannelActorAccountActor = MChannel & | 87 | export type MChannelActorAccountActor = |
88 | MChannel & | ||
79 | Use<'Account', MAccountActor> & | 89 | Use<'Account', MAccountActor> & |
80 | Use<'Actor', MActor> | 90 | Use<'Actor', MActor> |
81 | 91 | ||
82 | // ############################################################################ | 92 | // ############################################################################ |
83 | 93 | ||
84 | // Videos associations | 94 | // Videos associations |
85 | export type MChannelVideos = MChannel & | 95 | export type MChannelVideos = |
96 | MChannel & | ||
86 | Use<'Videos', MVideo[]> | 97 | Use<'Videos', MVideo[]> |
87 | 98 | ||
88 | export type MChannelActorAccountDefaultVideos = MChannel & | 99 | export type MChannelActorAccountDefaultVideos = |
100 | MChannel & | ||
89 | Use<'Actor', MActorDefault> & | 101 | Use<'Actor', MActorDefault> & |
90 | Use<'Account', MAccountDefault> & | 102 | Use<'Account', MAccountDefault> & |
91 | Use<'Videos', MVideo[]> | 103 | Use<'Videos', MVideo[]> |
@@ -94,14 +106,17 @@ export type MChannelActorAccountDefaultVideos = MChannel & | |||
94 | 106 | ||
95 | // For API | 107 | // For API |
96 | 108 | ||
97 | export type MChannelSummary = FunctionProperties<MChannel> & | 109 | export type MChannelSummary = |
110 | FunctionProperties<MChannel> & | ||
98 | Pick<MChannel, 'id' | 'name' | 'description' | 'actorId'> & | 111 | Pick<MChannel, 'id' | 'name' | 'description' | 'actorId'> & |
99 | Use<'Actor', MActorSummary> | 112 | Use<'Actor', MActorSummary> |
100 | 113 | ||
101 | export type MChannelSummaryAccount = MChannelSummary & | 114 | export type MChannelSummaryAccount = |
115 | MChannelSummary & | ||
102 | Use<'Account', MAccountSummaryBlocks> | 116 | Use<'Account', MAccountSummaryBlocks> |
103 | 117 | ||
104 | export type MChannelAPI = MChannel & | 118 | export type MChannelAPI = |
119 | MChannel & | ||
105 | Use<'Actor', MActorAPI> & | 120 | Use<'Actor', MActorAPI> & |
106 | Use<'Account', MAccountAPI> | 121 | Use<'Account', MAccountAPI> |
107 | 122 | ||
@@ -109,18 +124,22 @@ export type MChannelAPI = MChannel & | |||
109 | 124 | ||
110 | // Format for API or AP object | 125 | // Format for API or AP object |
111 | 126 | ||
112 | export type MChannelSummaryFormattable = FunctionProperties<MChannel> & | 127 | export type MChannelSummaryFormattable = |
128 | FunctionProperties<MChannel> & | ||
113 | Pick<MChannel, 'id' | 'name'> & | 129 | Pick<MChannel, 'id' | 'name'> & |
114 | Use<'Actor', MActorSummaryFormattable> | 130 | Use<'Actor', MActorSummaryFormattable> |
115 | 131 | ||
116 | export type MChannelAccountSummaryFormattable = MChannelSummaryFormattable & | 132 | export type MChannelAccountSummaryFormattable = |
133 | MChannelSummaryFormattable & | ||
117 | Use<'Account', MAccountSummaryFormattable> | 134 | Use<'Account', MAccountSummaryFormattable> |
118 | 135 | ||
119 | export type MChannelFormattable = FunctionProperties<MChannel> & | 136 | export type MChannelFormattable = |
137 | FunctionProperties<MChannel> & | ||
120 | Pick<MChannel, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'support'> & | 138 | Pick<MChannel, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'support'> & |
121 | Use<'Actor', MActorFormattable> & | 139 | Use<'Actor', MActorFormattable> & |
122 | PickWithOpt<VideoChannelModel, 'Account', MAccountFormattable> | 140 | PickWithOpt<VideoChannelModel, 'Account', MAccountFormattable> |
123 | 141 | ||
124 | export type MChannelAP = Pick<MChannel, 'name' | 'description' | 'support'> & | 142 | export type MChannelAP = |
143 | Pick<MChannel, 'name' | 'description' | 'support'> & | ||
125 | Use<'Actor', MActorAP> & | 144 | Use<'Actor', MActorAP> & |
126 | Use<'Account', MAccountUrl> | 145 | Use<'Account', MAccountUrl> |
diff --git a/server/typings/models/video/video-comment.ts b/server/typings/models/video/video-comment.ts index d693f9186..d6e0b66f5 100644 --- a/server/typings/models/video/video-comment.ts +++ b/server/typings/models/video/video-comment.ts | |||
@@ -14,30 +14,37 @@ export type MCommentUrl = Pick<MComment, 'url'> | |||
14 | 14 | ||
15 | // ############################################################################ | 15 | // ############################################################################ |
16 | 16 | ||
17 | export type MCommentOwner = MComment & | 17 | export type MCommentOwner = |
18 | MComment & | ||
18 | Use<'Account', MAccountDefault> | 19 | Use<'Account', MAccountDefault> |
19 | 20 | ||
20 | export type MCommentVideo = MComment & | 21 | export type MCommentVideo = |
22 | MComment & | ||
21 | Use<'Video', MVideoAccountLight> | 23 | Use<'Video', MVideoAccountLight> |
22 | 24 | ||
23 | export type MCommentReply = MComment & | 25 | export type MCommentReply = |
26 | MComment & | ||
24 | Use<'InReplyToVideoComment', MComment> | 27 | Use<'InReplyToVideoComment', MComment> |
25 | 28 | ||
26 | export type MCommentOwnerVideo = MComment & | 29 | export type MCommentOwnerVideo = |
30 | MComment & | ||
27 | Use<'Account', MAccountDefault> & | 31 | Use<'Account', MAccountDefault> & |
28 | Use<'Video', MVideoAccountLight> | 32 | Use<'Video', MVideoAccountLight> |
29 | 33 | ||
30 | export type MCommentOwnerVideoReply = MComment & | 34 | export type MCommentOwnerVideoReply = |
35 | MComment & | ||
31 | Use<'Account', MAccountDefault> & | 36 | Use<'Account', MAccountDefault> & |
32 | Use<'Video', MVideoAccountLight> & | 37 | Use<'Video', MVideoAccountLight> & |
33 | Use<'InReplyToVideoComment', MComment> | 38 | Use<'InReplyToVideoComment', MComment> |
34 | 39 | ||
35 | export type MCommentOwnerReplyVideoLight = MComment & | 40 | export type MCommentOwnerReplyVideoLight = |
41 | MComment & | ||
36 | Use<'Account', MAccountDefault> & | 42 | Use<'Account', MAccountDefault> & |
37 | Use<'InReplyToVideoComment', MComment> & | 43 | Use<'InReplyToVideoComment', MComment> & |
38 | Use<'Video', MVideoIdUrl> | 44 | Use<'Video', MVideoIdUrl> |
39 | 45 | ||
40 | export type MCommentOwnerVideoFeed = MCommentOwner & | 46 | export type MCommentOwnerVideoFeed = |
47 | MCommentOwner & | ||
41 | Use<'Video', MVideoFeed> | 48 | Use<'Video', MVideoFeed> |
42 | 49 | ||
43 | // ############################################################################ | 50 | // ############################################################################ |
@@ -48,10 +55,12 @@ export type MCommentAPI = MComment & { totalReplies: number } | |||
48 | 55 | ||
49 | // Format for API or AP object | 56 | // Format for API or AP object |
50 | 57 | ||
51 | export type MCommentFormattable = MCommentTotalReplies & | 58 | export type MCommentFormattable = |
59 | MCommentTotalReplies & | ||
52 | Use<'Account', MAccountFormattable> | 60 | Use<'Account', MAccountFormattable> |
53 | 61 | ||
54 | export type MCommentAP = MComment & | 62 | export type MCommentAP = |
63 | MComment & | ||
55 | Use<'Account', MAccountUrl> & | 64 | Use<'Account', MAccountUrl> & |
56 | PickWithOpt<VideoCommentModel, 'Video', MVideoUrl> & | 65 | PickWithOpt<VideoCommentModel, 'Video', MVideoUrl> & |
57 | PickWithOpt<VideoCommentModel, 'InReplyToVideoComment', MCommentUrl> | 66 | PickWithOpt<VideoCommentModel, 'InReplyToVideoComment', MCommentUrl> |
diff --git a/server/typings/models/video/video-file.ts b/server/typings/models/video/video-file.ts index 352fe3d32..3fcaca78f 100644 --- a/server/typings/models/video/video-file.ts +++ b/server/typings/models/video/video-file.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { VideoFileModel } from '../../../models/video/video-file' | 1 | import { VideoFileModel } from '../../../models/video/video-file' |
2 | import { PickWith, PickWithOpt } from '../../utils' | 2 | import { PickWith, PickWithOpt } from '../../utils' |
3 | import { MVideo, MVideoUUID } from './video' | 3 | import { MVideo, MVideoUUID } from './video' |
4 | import { MVideoRedundancyFileUrl } from './video-redundancy' | 4 | import { MVideoRedundancy, MVideoRedundancyFileUrl } from './video-redundancy' |
5 | import { MStreamingPlaylistVideo, MStreamingPlaylist } from './video-streaming-playlist' | 5 | import { MStreamingPlaylistVideo, MStreamingPlaylist } from './video-streaming-playlist' |
6 | 6 | ||
7 | type Use<K extends keyof VideoFileModel, M> = PickWith<VideoFileModel, K, M> | 7 | type Use<K extends keyof VideoFileModel, M> = PickWith<VideoFileModel, K, M> |
@@ -10,19 +10,28 @@ type Use<K extends keyof VideoFileModel, M> = PickWith<VideoFileModel, K, M> | |||
10 | 10 | ||
11 | export type MVideoFile = Omit<VideoFileModel, 'Video' | 'RedundancyVideos' | 'VideoStreamingPlaylist'> | 11 | export type MVideoFile = Omit<VideoFileModel, 'Video' | 'RedundancyVideos' | 'VideoStreamingPlaylist'> |
12 | 12 | ||
13 | export type MVideoFileVideo = MVideoFile & | 13 | export type MVideoFileVideo = |
14 | MVideoFile & | ||
14 | Use<'Video', MVideo> | 15 | Use<'Video', MVideo> |
15 | 16 | ||
16 | export type MVideoFileStreamingPlaylist = MVideoFile & | 17 | export type MVideoFileStreamingPlaylist = |
18 | MVideoFile & | ||
17 | Use<'VideoStreamingPlaylist', MStreamingPlaylist> | 19 | Use<'VideoStreamingPlaylist', MStreamingPlaylist> |
18 | 20 | ||
19 | export type MVideoFileStreamingPlaylistVideo = MVideoFile & | 21 | export type MVideoFileStreamingPlaylistVideo = |
22 | MVideoFile & | ||
20 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> | 23 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> |
21 | 24 | ||
22 | export type MVideoFileVideoUUID = MVideoFile & | 25 | export type MVideoFileVideoUUID = |
26 | MVideoFile & | ||
23 | Use<'Video', MVideoUUID> | 27 | Use<'Video', MVideoUUID> |
24 | 28 | ||
25 | export type MVideoFileRedundanciesOpt = MVideoFile & | 29 | export type MVideoFileRedundanciesAll = |
30 | MVideoFile & | ||
31 | PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancy[]> | ||
32 | |||
33 | export type MVideoFileRedundanciesOpt = | ||
34 | MVideoFile & | ||
26 | PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]> | 35 | PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]> |
27 | 36 | ||
28 | export function isStreamingPlaylistFile (file: any): file is MVideoFileStreamingPlaylist { | 37 | export function isStreamingPlaylistFile (file: any): file is MVideoFileStreamingPlaylist { |
diff --git a/server/typings/models/video/video-import.ts b/server/typings/models/video/video-import.ts index e119f17f9..4e5c2e4f0 100644 --- a/server/typings/models/video/video-import.ts +++ b/server/typings/models/video/video-import.ts | |||
@@ -9,18 +9,21 @@ type Use<K extends keyof VideoImportModel, M> = PickWith<VideoImportModel, K, M> | |||
9 | 9 | ||
10 | export type MVideoImport = Omit<VideoImportModel, 'User' | 'Video'> | 10 | export type MVideoImport = Omit<VideoImportModel, 'User' | 'Video'> |
11 | 11 | ||
12 | export type MVideoImportVideo = MVideoImport & | 12 | export type MVideoImportVideo = |
13 | MVideoImport & | ||
13 | Use<'Video', MVideo> | 14 | Use<'Video', MVideo> |
14 | 15 | ||
15 | // ############################################################################ | 16 | // ############################################################################ |
16 | 17 | ||
17 | type VideoAssociation = MVideoTag & MVideoAccountLight & MVideoThumbnail | 18 | type VideoAssociation = MVideoTag & MVideoAccountLight & MVideoThumbnail |
18 | 19 | ||
19 | export type MVideoImportDefault = MVideoImport & | 20 | export type MVideoImportDefault = |
21 | MVideoImport & | ||
20 | Use<'User', MUser> & | 22 | Use<'User', MUser> & |
21 | Use<'Video', VideoAssociation> | 23 | Use<'Video', VideoAssociation> |
22 | 24 | ||
23 | export type MVideoImportDefaultFiles = MVideoImport & | 25 | export type MVideoImportDefaultFiles = |
26 | MVideoImport & | ||
24 | Use<'User', MUser> & | 27 | Use<'User', MUser> & |
25 | Use<'Video', VideoAssociation & MVideoWithFile> | 28 | Use<'Video', VideoAssociation & MVideoWithFile> |
26 | 29 | ||
@@ -28,5 +31,6 @@ export type MVideoImportDefaultFiles = MVideoImport & | |||
28 | 31 | ||
29 | // Format for API or AP object | 32 | // Format for API or AP object |
30 | 33 | ||
31 | export type MVideoImportFormattable = MVideoImport & | 34 | export type MVideoImportFormattable = |
35 | MVideoImport & | ||
32 | PickWithOpt<VideoImportModel, 'Video', MVideoFormattable & MVideoTag> | 36 | PickWithOpt<VideoImportModel, 'Video', MVideoFormattable & MVideoTag> |
diff --git a/server/typings/models/video/video-playlist-element.ts b/server/typings/models/video/video-playlist-element.ts index 1aeff78d8..f33c76594 100644 --- a/server/typings/models/video/video-playlist-element.ts +++ b/server/typings/models/video/video-playlist-element.ts | |||
@@ -17,10 +17,12 @@ export type MVideoPlaylistElementLight = Pick<MVideoPlaylistElement, 'id' | 'vid | |||
17 | 17 | ||
18 | // ############################################################################ | 18 | // ############################################################################ |
19 | 19 | ||
20 | export type MVideoPlaylistVideoThumbnail = MVideoPlaylistElement & | 20 | export type MVideoPlaylistVideoThumbnail = |
21 | MVideoPlaylistElement & | ||
21 | Use<'Video', MVideoThumbnail> | 22 | Use<'Video', MVideoThumbnail> |
22 | 23 | ||
23 | export type MVideoPlaylistElementVideoUrlPlaylistPrivacy = MVideoPlaylistElement & | 24 | export type MVideoPlaylistElementVideoUrlPlaylistPrivacy = |
25 | MVideoPlaylistElement & | ||
24 | Use<'Video', MVideoUrl> & | 26 | Use<'Video', MVideoUrl> & |
25 | Use<'VideoPlaylist', MVideoPlaylistPrivacy> | 27 | Use<'VideoPlaylist', MVideoPlaylistPrivacy> |
26 | 28 | ||
@@ -28,8 +30,10 @@ export type MVideoPlaylistElementVideoUrlPlaylistPrivacy = MVideoPlaylistElement | |||
28 | 30 | ||
29 | // Format for API or AP object | 31 | // Format for API or AP object |
30 | 32 | ||
31 | export type MVideoPlaylistElementFormattable = MVideoPlaylistElement & | 33 | export type MVideoPlaylistElementFormattable = |
34 | MVideoPlaylistElement & | ||
32 | Use<'Video', MVideoFormattable> | 35 | Use<'Video', MVideoFormattable> |
33 | 36 | ||
34 | export type MVideoPlaylistElementAP = MVideoPlaylistElement & | 37 | export type MVideoPlaylistElementAP = |
38 | MVideoPlaylistElement & | ||
35 | Use<'Video', MVideoUrl> | 39 | Use<'Video', MVideoUrl> |
diff --git a/server/typings/models/video/video-playlist.ts b/server/typings/models/video/video-playlist.ts index a40c7aca9..49c27f4a7 100644 --- a/server/typings/models/video/video-playlist.ts +++ b/server/typings/models/video/video-playlist.ts | |||
@@ -22,30 +22,36 @@ export type MVideoPlaylistVideosLength = MVideoPlaylist & { videosLength?: numbe | |||
22 | 22 | ||
23 | // With elements | 23 | // With elements |
24 | 24 | ||
25 | export type MVideoPlaylistWithElements = MVideoPlaylist & | 25 | export type MVideoPlaylistWithElements = |
26 | MVideoPlaylist & | ||
26 | Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]> | 27 | Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]> |
27 | 28 | ||
28 | export type MVideoPlaylistIdWithElements = MVideoPlaylistId & | 29 | export type MVideoPlaylistIdWithElements = |
30 | MVideoPlaylistId & | ||
29 | Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]> | 31 | Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]> |
30 | 32 | ||
31 | // ############################################################################ | 33 | // ############################################################################ |
32 | 34 | ||
33 | // With account | 35 | // With account |
34 | 36 | ||
35 | export type MVideoPlaylistOwner = MVideoPlaylist & | 37 | export type MVideoPlaylistOwner = |
38 | MVideoPlaylist & | ||
36 | Use<'OwnerAccount', MAccount> | 39 | Use<'OwnerAccount', MAccount> |
37 | 40 | ||
38 | export type MVideoPlaylistOwnerDefault = MVideoPlaylist & | 41 | export type MVideoPlaylistOwnerDefault = |
42 | MVideoPlaylist & | ||
39 | Use<'OwnerAccount', MAccountDefault> | 43 | Use<'OwnerAccount', MAccountDefault> |
40 | 44 | ||
41 | // ############################################################################ | 45 | // ############################################################################ |
42 | 46 | ||
43 | // With thumbnail | 47 | // With thumbnail |
44 | 48 | ||
45 | export type MVideoPlaylistThumbnail = MVideoPlaylist & | 49 | export type MVideoPlaylistThumbnail = |
50 | MVideoPlaylist & | ||
46 | Use<'Thumbnail', MThumbnail> | 51 | Use<'Thumbnail', MThumbnail> |
47 | 52 | ||
48 | export type MVideoPlaylistAccountThumbnail = MVideoPlaylist & | 53 | export type MVideoPlaylistAccountThumbnail = |
54 | MVideoPlaylist & | ||
49 | Use<'OwnerAccount', MAccountDefault> & | 55 | Use<'OwnerAccount', MAccountDefault> & |
50 | Use<'Thumbnail', MThumbnail> | 56 | Use<'Thumbnail', MThumbnail> |
51 | 57 | ||
@@ -53,7 +59,8 @@ export type MVideoPlaylistAccountThumbnail = MVideoPlaylist & | |||
53 | 59 | ||
54 | // With channel | 60 | // With channel |
55 | 61 | ||
56 | export type MVideoPlaylistAccountChannelDefault = MVideoPlaylist & | 62 | export type MVideoPlaylistAccountChannelDefault = |
63 | MVideoPlaylist & | ||
57 | Use<'OwnerAccount', MAccountDefault> & | 64 | Use<'OwnerAccount', MAccountDefault> & |
58 | Use<'VideoChannel', MChannelDefault> | 65 | Use<'VideoChannel', MChannelDefault> |
59 | 66 | ||
@@ -61,7 +68,8 @@ export type MVideoPlaylistAccountChannelDefault = MVideoPlaylist & | |||
61 | 68 | ||
62 | // With all associations | 69 | // With all associations |
63 | 70 | ||
64 | export type MVideoPlaylistFull = MVideoPlaylist & | 71 | export type MVideoPlaylistFull = |
72 | MVideoPlaylist & | ||
65 | Use<'OwnerAccount', MAccountDefault> & | 73 | Use<'OwnerAccount', MAccountDefault> & |
66 | Use<'VideoChannel', MChannelDefault> & | 74 | Use<'VideoChannel', MChannelDefault> & |
67 | Use<'Thumbnail', MThumbnail> | 75 | Use<'Thumbnail', MThumbnail> |
@@ -70,11 +78,13 @@ export type MVideoPlaylistFull = MVideoPlaylist & | |||
70 | 78 | ||
71 | // For API | 79 | // For API |
72 | 80 | ||
73 | export type MVideoPlaylistAccountChannelSummary = MVideoPlaylist & | 81 | export type MVideoPlaylistAccountChannelSummary = |
82 | MVideoPlaylist & | ||
74 | Use<'OwnerAccount', MAccountSummary> & | 83 | Use<'OwnerAccount', MAccountSummary> & |
75 | Use<'VideoChannel', MChannelSummary> | 84 | Use<'VideoChannel', MChannelSummary> |
76 | 85 | ||
77 | export type MVideoPlaylistFullSummary = MVideoPlaylist & | 86 | export type MVideoPlaylistFullSummary = |
87 | MVideoPlaylist & | ||
78 | Use<'Thumbnail', MThumbnail> & | 88 | Use<'Thumbnail', MThumbnail> & |
79 | Use<'OwnerAccount', MAccountSummary> & | 89 | Use<'OwnerAccount', MAccountSummary> & |
80 | Use<'VideoChannel', MChannelSummary> | 90 | Use<'VideoChannel', MChannelSummary> |
@@ -83,10 +93,12 @@ export type MVideoPlaylistFullSummary = MVideoPlaylist & | |||
83 | 93 | ||
84 | // Format for API or AP object | 94 | // Format for API or AP object |
85 | 95 | ||
86 | export type MVideoPlaylistFormattable = MVideoPlaylistVideosLength & | 96 | export type MVideoPlaylistFormattable = |
97 | MVideoPlaylistVideosLength & | ||
87 | Use<'OwnerAccount', MAccountSummaryFormattable> & | 98 | Use<'OwnerAccount', MAccountSummaryFormattable> & |
88 | Use<'VideoChannel', MChannelSummaryFormattable> | 99 | Use<'VideoChannel', MChannelSummaryFormattable> |
89 | 100 | ||
90 | export type MVideoPlaylistAP = MVideoPlaylist & | 101 | export type MVideoPlaylistAP = |
102 | MVideoPlaylist & | ||
91 | Use<'Thumbnail', MThumbnail> & | 103 | Use<'Thumbnail', MThumbnail> & |
92 | Use<'VideoChannel', MChannelUrl> | 104 | Use<'VideoChannel', MChannelUrl> |
diff --git a/server/typings/models/video/video-rate.ts b/server/typings/models/video/video-rate.ts index f6bb527fc..64ce4965b 100644 --- a/server/typings/models/video/video-rate.ts +++ b/server/typings/models/video/video-rate.ts | |||
@@ -9,10 +9,12 @@ type Use<K extends keyof AccountVideoRateModel, M> = PickWith<AccountVideoRateMo | |||
9 | 9 | ||
10 | export type MAccountVideoRate = Omit<AccountVideoRateModel, 'Video' | 'Account'> | 10 | export type MAccountVideoRate = Omit<AccountVideoRateModel, 'Video' | 'Account'> |
11 | 11 | ||
12 | export type MAccountVideoRateAccountUrl = MAccountVideoRate & | 12 | export type MAccountVideoRateAccountUrl = |
13 | MAccountVideoRate & | ||
13 | Use<'Account', MAccountUrl> | 14 | Use<'Account', MAccountUrl> |
14 | 15 | ||
15 | export type MAccountVideoRateAccountVideo = MAccountVideoRate & | 16 | export type MAccountVideoRateAccountVideo = |
17 | MAccountVideoRate & | ||
16 | Use<'Account', MAccountAudience> & | 18 | Use<'Account', MAccountAudience> & |
17 | Use<'Video', MVideo> | 19 | Use<'Video', MVideo> |
18 | 20 | ||
@@ -20,5 +22,6 @@ export type MAccountVideoRateAccountVideo = MAccountVideoRate & | |||
20 | 22 | ||
21 | // Format for API or AP object | 23 | // Format for API or AP object |
22 | 24 | ||
23 | export type MAccountVideoRateFormattable = Pick<MAccountVideoRate, 'type'> & | 25 | export type MAccountVideoRateFormattable = |
26 | Pick<MAccountVideoRate, 'type'> & | ||
24 | Use<'Video', MVideoFormattable> | 27 | Use<'Video', MVideoFormattable> |
diff --git a/server/typings/models/video/video-redundancy.ts b/server/typings/models/video/video-redundancy.ts index 25bdac057..5107aa7f4 100644 --- a/server/typings/models/video/video-redundancy.ts +++ b/server/typings/models/video/video-redundancy.ts | |||
@@ -16,16 +16,20 @@ export type MVideoRedundancyFileUrl = Pick<MVideoRedundancy, 'fileUrl'> | |||
16 | 16 | ||
17 | // ############################################################################ | 17 | // ############################################################################ |
18 | 18 | ||
19 | export type MVideoRedundancyFile = MVideoRedundancy & | 19 | export type MVideoRedundancyFile = |
20 | MVideoRedundancy & | ||
20 | Use<'VideoFile', MVideoFile> | 21 | Use<'VideoFile', MVideoFile> |
21 | 22 | ||
22 | export type MVideoRedundancyFileVideo = MVideoRedundancy & | 23 | export type MVideoRedundancyFileVideo = |
24 | MVideoRedundancy & | ||
23 | Use<'VideoFile', MVideoFileVideo> | 25 | Use<'VideoFile', MVideoFileVideo> |
24 | 26 | ||
25 | export type MVideoRedundancyStreamingPlaylistVideo = MVideoRedundancy & | 27 | export type MVideoRedundancyStreamingPlaylistVideo = |
28 | MVideoRedundancy & | ||
26 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> | 29 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> |
27 | 30 | ||
28 | export type MVideoRedundancyVideo = MVideoRedundancy & | 31 | export type MVideoRedundancyVideo = |
32 | MVideoRedundancy & | ||
29 | Use<'VideoFile', MVideoFileVideo> & | 33 | Use<'VideoFile', MVideoFileVideo> & |
30 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> | 34 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> |
31 | 35 | ||
@@ -33,6 +37,7 @@ export type MVideoRedundancyVideo = MVideoRedundancy & | |||
33 | 37 | ||
34 | // Format for API or AP object | 38 | // Format for API or AP object |
35 | 39 | ||
36 | export type MVideoRedundancyAP = MVideoRedundancy & | 40 | export type MVideoRedundancyAP = |
41 | MVideoRedundancy & | ||
37 | PickWithOpt<VideoRedundancyModel, 'VideoFile', MVideoFile & PickWith<VideoFileModel, 'Video', MVideoUrl>> & | 42 | PickWithOpt<VideoRedundancyModel, 'VideoFile', MVideoFile & PickWith<VideoFileModel, 'Video', MVideoUrl>> & |
38 | PickWithOpt<VideoRedundancyModel, 'VideoStreamingPlaylist', PickWith<VideoStreamingPlaylistModel, 'Video', MVideoUrl>> | 43 | PickWithOpt<VideoRedundancyModel, 'VideoStreamingPlaylist', PickWith<VideoStreamingPlaylistModel, 'Video', MVideoUrl>> |
diff --git a/server/typings/models/video/video-share.ts b/server/typings/models/video/video-share.ts index a7a90beeb..50ca75d26 100644 --- a/server/typings/models/video/video-share.ts +++ b/server/typings/models/video/video-share.ts | |||
@@ -9,9 +9,11 @@ type Use<K extends keyof VideoShareModel, M> = PickWith<VideoShareModel, K, M> | |||
9 | 9 | ||
10 | export type MVideoShare = Omit<VideoShareModel, 'Actor' | 'Video'> | 10 | export type MVideoShare = Omit<VideoShareModel, 'Actor' | 'Video'> |
11 | 11 | ||
12 | export type MVideoShareActor = MVideoShare & | 12 | export type MVideoShareActor = |
13 | MVideoShare & | ||
13 | Use<'Actor', MActorDefault> | 14 | Use<'Actor', MActorDefault> |
14 | 15 | ||
15 | export type MVideoShareFull = MVideoShare & | 16 | export type MVideoShareFull = |
17 | MVideoShare & | ||
16 | Use<'Actor', MActorDefault> & | 18 | Use<'Actor', MActorDefault> & |
17 | Use<'Video', MVideo> | 19 | Use<'Video', MVideo> |
diff --git a/server/typings/models/video/video-streaming-playlist.ts b/server/typings/models/video/video-streaming-playlist.ts index 436c0c072..3f54aa560 100644 --- a/server/typings/models/video/video-streaming-playlist.ts +++ b/server/typings/models/video/video-streaming-playlist.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { VideoStreamingPlaylistModel } from '../../../models/video/video-streaming-playlist' | 1 | import { VideoStreamingPlaylistModel } from '../../../models/video/video-streaming-playlist' |
2 | import { PickWith, PickWithOpt } from '../../utils' | 2 | import { PickWith, PickWithOpt } from '../../utils' |
3 | import { MVideoRedundancyFileUrl } from './video-redundancy' | 3 | import { MVideoRedundancyFileUrl, MVideoRedundancy } from './video-redundancy' |
4 | import { MVideo } from './video' | 4 | import { MVideo } from './video' |
5 | import { MVideoFile } from './video-file' | 5 | import { MVideoFile } from './video-file' |
6 | 6 | ||
@@ -10,21 +10,31 @@ type Use<K extends keyof VideoStreamingPlaylistModel, M> = PickWith<VideoStreami | |||
10 | 10 | ||
11 | export type MStreamingPlaylist = Omit<VideoStreamingPlaylistModel, 'Video' | 'RedundancyVideos' | 'VideoFiles'> | 11 | export type MStreamingPlaylist = Omit<VideoStreamingPlaylistModel, 'Video' | 'RedundancyVideos' | 'VideoFiles'> |
12 | 12 | ||
13 | export type MStreamingPlaylistFiles = MStreamingPlaylist & | 13 | export type MStreamingPlaylistFiles = |
14 | MStreamingPlaylist & | ||
14 | Use<'VideoFiles', MVideoFile[]> | 15 | Use<'VideoFiles', MVideoFile[]> |
15 | 16 | ||
16 | export type MStreamingPlaylistVideo = MStreamingPlaylist & | 17 | export type MStreamingPlaylistVideo = |
18 | MStreamingPlaylist & | ||
17 | Use<'Video', MVideo> | 19 | Use<'Video', MVideo> |
18 | 20 | ||
19 | export type MStreamingPlaylistFilesVideo = MStreamingPlaylist & | 21 | export type MStreamingPlaylistFilesVideo = |
22 | MStreamingPlaylist & | ||
20 | Use<'VideoFiles', MVideoFile[]> & | 23 | Use<'VideoFiles', MVideoFile[]> & |
21 | Use<'Video', MVideo> | 24 | Use<'Video', MVideo> |
22 | 25 | ||
23 | export type MStreamingPlaylistRedundancies = MStreamingPlaylist & | 26 | export type MStreamingPlaylistRedundanciesAll = |
27 | MStreamingPlaylist & | ||
28 | Use<'VideoFiles', MVideoFile[]> & | ||
29 | Use<'RedundancyVideos', MVideoRedundancy[]> | ||
30 | |||
31 | export type MStreamingPlaylistRedundancies = | ||
32 | MStreamingPlaylist & | ||
24 | Use<'VideoFiles', MVideoFile[]> & | 33 | Use<'VideoFiles', MVideoFile[]> & |
25 | Use<'RedundancyVideos', MVideoRedundancyFileUrl[]> | 34 | Use<'RedundancyVideos', MVideoRedundancyFileUrl[]> |
26 | 35 | ||
27 | export type MStreamingPlaylistRedundanciesOpt = MStreamingPlaylist & | 36 | export type MStreamingPlaylistRedundanciesOpt = |
37 | MStreamingPlaylist & | ||
28 | Use<'VideoFiles', MVideoFile[]> & | 38 | Use<'VideoFiles', MVideoFile[]> & |
29 | PickWithOpt<VideoStreamingPlaylistModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]> | 39 | PickWithOpt<VideoStreamingPlaylistModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]> |
30 | 40 | ||
diff --git a/server/typings/models/video/video.ts b/server/typings/models/video/video.ts index 7f69a91de..7eff0a913 100644 --- a/server/typings/models/video/video.ts +++ b/server/typings/models/video/video.ts | |||
@@ -9,9 +9,14 @@ import { | |||
9 | MChannelUserId | 9 | MChannelUserId |
10 | } from './video-channels' | 10 | } from './video-channels' |
11 | import { MTag } from './tag' | 11 | import { MTag } from './tag' |
12 | import { MVideoCaptionLanguage } from './video-caption' | 12 | import { MVideoCaptionLanguage, MVideoCaptionLanguageUrl } from './video-caption' |
13 | import { MStreamingPlaylistFiles, MStreamingPlaylistRedundancies, MStreamingPlaylistRedundanciesOpt } from './video-streaming-playlist' | 13 | import { |
14 | import { MVideoFile, MVideoFileRedundanciesOpt } from './video-file' | 14 | MStreamingPlaylistFiles, |
15 | MStreamingPlaylistRedundancies, | ||
16 | MStreamingPlaylistRedundanciesAll, | ||
17 | MStreamingPlaylistRedundanciesOpt | ||
18 | } from './video-streaming-playlist' | ||
19 | import { MVideoFile, MVideoFileRedundanciesAll, MVideoFileRedundanciesOpt } from './video-file' | ||
15 | import { MThumbnail } from './thumbnail' | 20 | import { MThumbnail } from './thumbnail' |
16 | import { MVideoBlacklist, MVideoBlacklistLight, MVideoBlacklistUnfederated } from './video-blacklist' | 21 | import { MVideoBlacklist, MVideoBlacklistLight, MVideoBlacklistUnfederated } from './video-blacklist' |
17 | import { MScheduleVideoUpdate } from './schedule-video-update' | 22 | import { MScheduleVideoUpdate } from './schedule-video-update' |
@@ -21,7 +26,8 @@ type Use<K extends keyof VideoModel, M> = PickWith<VideoModel, K, M> | |||
21 | 26 | ||
22 | // ############################################################################ | 27 | // ############################################################################ |
23 | 28 | ||
24 | export type MVideo = Omit<VideoModel, 'VideoChannel' | 'Tags' | 'Thumbnails' | 'VideoPlaylistElements' | 'VideoAbuses' | | 29 | export type MVideo = |
30 | Omit<VideoModel, 'VideoChannel' | 'Tags' | 'Thumbnails' | 'VideoPlaylistElements' | 'VideoAbuses' | | ||
25 | 'VideoFiles' | 'VideoStreamingPlaylists' | 'VideoShares' | 'AccountVideoRates' | 'VideoComments' | 'VideoViews' | 'UserVideoHistories' | | 31 | 'VideoFiles' | 'VideoStreamingPlaylists' | 'VideoShares' | 'AccountVideoRates' | 'VideoComments' | 'VideoViews' | 'UserVideoHistories' | |
26 | 'ScheduleVideoUpdate' | 'VideoBlacklist' | 'VideoImport' | 'VideoCaptions'> | 32 | 'ScheduleVideoUpdate' | 'VideoBlacklist' | 'VideoImport' | 'VideoCaptions'> |
27 | 33 | ||
@@ -39,50 +45,63 @@ export type MVideoFeed = Pick<MVideo, 'name' | 'uuid'> | |||
39 | // Video raw associations: schedules, video files, tags, thumbnails, captions, streaming playlists | 45 | // Video raw associations: schedules, video files, tags, thumbnails, captions, streaming playlists |
40 | 46 | ||
41 | // "With" to not confuse with the VideoFile model | 47 | // "With" to not confuse with the VideoFile model |
42 | export type MVideoWithFile = MVideo & | 48 | export type MVideoWithFile = |
49 | MVideo & | ||
43 | Use<'VideoFiles', MVideoFile[]> & | 50 | Use<'VideoFiles', MVideoFile[]> & |
44 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> | 51 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> |
45 | 52 | ||
46 | export type MVideoThumbnail = MVideo & | 53 | export type MVideoThumbnail = |
54 | MVideo & | ||
47 | Use<'Thumbnails', MThumbnail[]> | 55 | Use<'Thumbnails', MThumbnail[]> |
48 | 56 | ||
49 | export type MVideoIdThumbnail = MVideoId & | 57 | export type MVideoIdThumbnail = |
58 | MVideoId & | ||
50 | Use<'Thumbnails', MThumbnail[]> | 59 | Use<'Thumbnails', MThumbnail[]> |
51 | 60 | ||
52 | export type MVideoWithFileThumbnail = MVideo & | 61 | export type MVideoWithFileThumbnail = |
62 | MVideo & | ||
53 | Use<'VideoFiles', MVideoFile[]> & | 63 | Use<'VideoFiles', MVideoFile[]> & |
54 | Use<'Thumbnails', MThumbnail[]> | 64 | Use<'Thumbnails', MThumbnail[]> |
55 | 65 | ||
56 | export type MVideoThumbnailBlacklist = MVideo & | 66 | export type MVideoThumbnailBlacklist = |
67 | MVideo & | ||
57 | Use<'Thumbnails', MThumbnail[]> & | 68 | Use<'Thumbnails', MThumbnail[]> & |
58 | Use<'VideoBlacklist', MVideoBlacklistLight> | 69 | Use<'VideoBlacklist', MVideoBlacklistLight> |
59 | 70 | ||
60 | export type MVideoTag = MVideo & | 71 | export type MVideoTag = |
72 | MVideo & | ||
61 | Use<'Tags', MTag[]> | 73 | Use<'Tags', MTag[]> |
62 | 74 | ||
63 | export type MVideoWithSchedule = MVideo & | 75 | export type MVideoWithSchedule = |
76 | MVideo & | ||
64 | PickWithOpt<VideoModel, 'ScheduleVideoUpdate', MScheduleVideoUpdate> | 77 | PickWithOpt<VideoModel, 'ScheduleVideoUpdate', MScheduleVideoUpdate> |
65 | 78 | ||
66 | export type MVideoWithCaptions = MVideo & | 79 | export type MVideoWithCaptions = |
80 | MVideo & | ||
67 | Use<'VideoCaptions', MVideoCaptionLanguage[]> | 81 | Use<'VideoCaptions', MVideoCaptionLanguage[]> |
68 | 82 | ||
69 | export type MVideoWithStreamingPlaylist = MVideo & | 83 | export type MVideoWithStreamingPlaylist = |
84 | MVideo & | ||
70 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> | 85 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> |
71 | 86 | ||
72 | // ############################################################################ | 87 | // ############################################################################ |
73 | 88 | ||
74 | // Associations with not all their attributes | 89 | // Associations with not all their attributes |
75 | 90 | ||
76 | export type MVideoUserHistory = MVideo & | 91 | export type MVideoUserHistory = |
92 | MVideo & | ||
77 | Use<'UserVideoHistories', MUserVideoHistoryTime[]> | 93 | Use<'UserVideoHistories', MUserVideoHistoryTime[]> |
78 | 94 | ||
79 | export type MVideoWithBlacklistLight = MVideo & | 95 | export type MVideoWithBlacklistLight = |
96 | MVideo & | ||
80 | Use<'VideoBlacklist', MVideoBlacklistLight> | 97 | Use<'VideoBlacklist', MVideoBlacklistLight> |
81 | 98 | ||
82 | export type MVideoAccountLight = MVideo & | 99 | export type MVideoAccountLight = |
100 | MVideo & | ||
83 | Use<'VideoChannel', MChannelAccountLight> | 101 | Use<'VideoChannel', MChannelAccountLight> |
84 | 102 | ||
85 | export type MVideoWithRights = MVideo & | 103 | export type MVideoWithRights = |
104 | MVideo & | ||
86 | Use<'VideoBlacklist', MVideoBlacklistLight> & | 105 | Use<'VideoBlacklist', MVideoBlacklistLight> & |
87 | Use<'Thumbnails', MThumbnail[]> & | 106 | Use<'Thumbnails', MThumbnail[]> & |
88 | Use<'VideoChannel', MChannelUserId> | 107 | Use<'VideoChannel', MChannelUserId> |
@@ -91,12 +110,14 @@ export type MVideoWithRights = MVideo & | |||
91 | 110 | ||
92 | // All files with some additional associations | 111 | // All files with some additional associations |
93 | 112 | ||
94 | export type MVideoWithAllFiles = MVideo & | 113 | export type MVideoWithAllFiles = |
114 | MVideo & | ||
95 | Use<'VideoFiles', MVideoFile[]> & | 115 | Use<'VideoFiles', MVideoFile[]> & |
96 | Use<'Thumbnails', MThumbnail[]> & | 116 | Use<'Thumbnails', MThumbnail[]> & |
97 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> | 117 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> |
98 | 118 | ||
99 | export type MVideoAccountLightBlacklistAllFiles = MVideo & | 119 | export type MVideoAccountLightBlacklistAllFiles = |
120 | MVideo & | ||
100 | Use<'VideoFiles', MVideoFile[]> & | 121 | Use<'VideoFiles', MVideoFile[]> & |
101 | Use<'Thumbnails', MThumbnail[]> & | 122 | Use<'Thumbnails', MThumbnail[]> & |
102 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> & | 123 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> & |
@@ -107,17 +128,21 @@ export type MVideoAccountLightBlacklistAllFiles = MVideo & | |||
107 | 128 | ||
108 | // With account | 129 | // With account |
109 | 130 | ||
110 | export type MVideoAccountDefault = MVideo & | 131 | export type MVideoAccountDefault = |
132 | MVideo & | ||
111 | Use<'VideoChannel', MChannelAccountDefault> | 133 | Use<'VideoChannel', MChannelAccountDefault> |
112 | 134 | ||
113 | export type MVideoThumbnailAccountDefault = MVideo & | 135 | export type MVideoThumbnailAccountDefault = |
136 | MVideo & | ||
114 | Use<'Thumbnails', MThumbnail[]> & | 137 | Use<'Thumbnails', MThumbnail[]> & |
115 | Use<'VideoChannel', MChannelAccountDefault> | 138 | Use<'VideoChannel', MChannelAccountDefault> |
116 | 139 | ||
117 | export type MVideoWithChannelActor = MVideo & | 140 | export type MVideoWithChannelActor = |
141 | MVideo & | ||
118 | Use<'VideoChannel', MChannelActor> | 142 | Use<'VideoChannel', MChannelActor> |
119 | 143 | ||
120 | export type MVideoFullLight = MVideo & | 144 | export type MVideoFullLight = |
145 | MVideo & | ||
121 | Use<'Thumbnails', MThumbnail[]> & | 146 | Use<'Thumbnails', MThumbnail[]> & |
122 | Use<'VideoBlacklist', MVideoBlacklistLight> & | 147 | Use<'VideoBlacklist', MVideoBlacklistLight> & |
123 | Use<'Tags', MTag[]> & | 148 | Use<'Tags', MTag[]> & |
@@ -131,18 +156,20 @@ export type MVideoFullLight = MVideo & | |||
131 | 156 | ||
132 | // API | 157 | // API |
133 | 158 | ||
134 | export type MVideoAP = MVideo & | 159 | export type MVideoAP = |
160 | MVideo & | ||
135 | Use<'Tags', MTag[]> & | 161 | Use<'Tags', MTag[]> & |
136 | Use<'VideoChannel', MChannelAccountLight> & | 162 | Use<'VideoChannel', MChannelAccountLight> & |
137 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> & | 163 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> & |
138 | Use<'VideoCaptions', MVideoCaptionLanguage[]> & | 164 | Use<'VideoCaptions', MVideoCaptionLanguageUrl[]> & |
139 | Use<'VideoBlacklist', MVideoBlacklistUnfederated> & | 165 | Use<'VideoBlacklist', MVideoBlacklistUnfederated> & |
140 | Use<'VideoFiles', MVideoFileRedundanciesOpt[]> & | 166 | Use<'VideoFiles', MVideoFileRedundanciesOpt[]> & |
141 | Use<'Thumbnails', MThumbnail[]> | 167 | Use<'Thumbnails', MThumbnail[]> |
142 | 168 | ||
143 | export type MVideoAPWithoutCaption = Omit<MVideoAP, 'VideoCaptions'> | 169 | export type MVideoAPWithoutCaption = Omit<MVideoAP, 'VideoCaptions'> |
144 | 170 | ||
145 | export type MVideoDetails = MVideo & | 171 | export type MVideoDetails = |
172 | MVideo & | ||
146 | Use<'VideoBlacklist', MVideoBlacklistLight> & | 173 | Use<'VideoBlacklist', MVideoBlacklistLight> & |
147 | Use<'Tags', MTag[]> & | 174 | Use<'Tags', MTag[]> & |
148 | Use<'VideoChannel', MChannelAccountLight> & | 175 | Use<'VideoChannel', MChannelAccountLight> & |
@@ -152,23 +179,31 @@ export type MVideoDetails = MVideo & | |||
152 | Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundancies[]> & | 179 | Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundancies[]> & |
153 | Use<'VideoFiles', MVideoFileRedundanciesOpt[]> | 180 | Use<'VideoFiles', MVideoFileRedundanciesOpt[]> |
154 | 181 | ||
155 | export type MVideoForUser = MVideo & | 182 | export type MVideoForUser = |
183 | MVideo & | ||
156 | Use<'VideoChannel', MChannelAccountDefault> & | 184 | Use<'VideoChannel', MChannelAccountDefault> & |
157 | Use<'ScheduleVideoUpdate', MScheduleVideoUpdate> & | 185 | Use<'ScheduleVideoUpdate', MScheduleVideoUpdate> & |
158 | Use<'VideoBlacklist', MVideoBlacklistLight> & | 186 | Use<'VideoBlacklist', MVideoBlacklistLight> & |
159 | Use<'Thumbnails', MThumbnail[]> | 187 | Use<'Thumbnails', MThumbnail[]> |
160 | 188 | ||
189 | export type MVideoForRedundancyAPI = | ||
190 | MVideo & | ||
191 | Use<'VideoFiles', MVideoFileRedundanciesAll[]> & | ||
192 | Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesAll[]> | ||
193 | |||
161 | // ############################################################################ | 194 | // ############################################################################ |
162 | 195 | ||
163 | // Format for API or AP object | 196 | // Format for API or AP object |
164 | 197 | ||
165 | export type MVideoFormattable = MVideo & | 198 | export type MVideoFormattable = |
199 | MVideo & | ||
166 | PickWithOpt<VideoModel, 'UserVideoHistories', MUserVideoHistoryTime[]> & | 200 | PickWithOpt<VideoModel, 'UserVideoHistories', MUserVideoHistoryTime[]> & |
167 | Use<'VideoChannel', MChannelAccountSummaryFormattable> & | 201 | Use<'VideoChannel', MChannelAccountSummaryFormattable> & |
168 | PickWithOpt<VideoModel, 'ScheduleVideoUpdate', Pick<MScheduleVideoUpdate, 'updateAt' | 'privacy'>> & | 202 | PickWithOpt<VideoModel, 'ScheduleVideoUpdate', Pick<MScheduleVideoUpdate, 'updateAt' | 'privacy'>> & |
169 | PickWithOpt<VideoModel, 'VideoBlacklist', Pick<MVideoBlacklist, 'reason'>> | 203 | PickWithOpt<VideoModel, 'VideoBlacklist', Pick<MVideoBlacklist, 'reason'>> |
170 | 204 | ||
171 | export type MVideoFormattableDetails = MVideoFormattable & | 205 | export type MVideoFormattableDetails = |
206 | MVideoFormattable & | ||
172 | Use<'VideoChannel', MChannelFormattable> & | 207 | Use<'VideoChannel', MChannelFormattable> & |
173 | Use<'Tags', MTag[]> & | 208 | Use<'Tags', MTag[]> & |
174 | Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesOpt[]> & | 209 | Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesOpt[]> & |
diff --git a/server/typings/utils.ts b/server/typings/utils.ts index 24d43b258..55500d8c4 100644 --- a/server/typings/utils.ts +++ b/server/typings/utils.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | /* eslint-disable @typescript-eslint/array-type */ | ||
2 | |||
1 | export type FunctionPropertyNames<T> = { | 3 | export type FunctionPropertyNames<T> = { |
2 | [K in keyof T]: T[K] extends Function ? K : never | 4 | [K in keyof T]: T[K] extends Function ? K : never |
3 | }[keyof T] | 5 | }[keyof T] |
diff --git a/shared/core-utils/miscs/miscs.ts b/shared/core-utils/miscs/miscs.ts index 5de024c08..1eee22d82 100644 --- a/shared/core-utils/miscs/miscs.ts +++ b/shared/core-utils/miscs/miscs.ts | |||
@@ -11,7 +11,7 @@ function compareSemVer (a: string, b: string) { | |||
11 | const l = Math.min(segmentsA.length, segmentsB.length) | 11 | const l = Math.min(segmentsA.length, segmentsB.length) |
12 | 12 | ||
13 | for (let i = 0; i < l; i++) { | 13 | for (let i = 0; i < l; i++) { |
14 | const diff = parseInt(segmentsA[ i ], 10) - parseInt(segmentsB[ i ], 10) | 14 | const diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10) |
15 | 15 | ||
16 | if (diff) return diff | 16 | if (diff) return diff |
17 | } | 17 | } |
diff --git a/shared/extra-utils/instances-index/mock-instances-index.ts b/shared/extra-utils/instances-index/mock-instances-index.ts index cfa4523c1..c58e8bcf8 100644 --- a/shared/extra-utils/instances-index/mock-instances-index.ts +++ b/shared/extra-utils/instances-index/mock-instances-index.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | 2 | ||
3 | export class MockInstancesIndex { | 3 | export class MockInstancesIndex { |
4 | private indexInstances: { host: string, createdAt: string }[] = [] | 4 | private readonly indexInstances: { host: string, createdAt: string }[] = [] |
5 | 5 | ||
6 | initialize () { | 6 | initialize () { |
7 | return new Promise(res => { | 7 | return new Promise(res => { |
diff --git a/shared/extra-utils/miscs/miscs.ts b/shared/extra-utils/miscs/miscs.ts index 6b0f6d990..f4e86b85a 100644 --- a/shared/extra-utils/miscs/miscs.ts +++ b/shared/extra-utils/miscs/miscs.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import { basename, dirname, isAbsolute, join, resolve } from 'path' | 4 | import { basename, dirname, isAbsolute, join, resolve } from 'path' |
@@ -10,11 +10,11 @@ import * as ffmpeg from 'fluent-ffmpeg' | |||
10 | const expect = chai.expect | 10 | const expect = chai.expect |
11 | let webtorrent: WebTorrent.Instance | 11 | let webtorrent: WebTorrent.Instance |
12 | 12 | ||
13 | function immutableAssign <T, U> (target: T, source: U) { | 13 | function immutableAssign<T, U> (target: T, source: U) { |
14 | return Object.assign<{}, T, U>({}, target, source) | 14 | return Object.assign<{}, T, U>({}, target, source) |
15 | } | 15 | } |
16 | 16 | ||
17 | // Default interval -> 5 minutes | 17 | // Default interval -> 5 minutes |
18 | function dateIsValid (dateString: string, interval = 300000) { | 18 | function dateIsValid (dateString: string, interval = 300000) { |
19 | const dateToCheck = new Date(dateString) | 19 | const dateToCheck = new Date(dateString) |
20 | const now = new Date() | 20 | const now = new Date() |
@@ -89,7 +89,7 @@ async function generateHighBitrateVideo () { | |||
89 | // a large file in the repo. The video needs to have a certain minimum length so | 89 | // a large file in the repo. The video needs to have a certain minimum length so |
90 | // that FFmpeg properly applies bitrate limits. | 90 | // that FFmpeg properly applies bitrate limits. |
91 | // https://stackoverflow.com/a/15795112 | 91 | // https://stackoverflow.com/a/15795112 |
92 | return new Promise<string>(async (res, rej) => { | 92 | return new Promise<string>((res, rej) => { |
93 | ffmpeg() | 93 | ffmpeg() |
94 | .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ]) | 94 | .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ]) |
95 | .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) | 95 | .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) |
@@ -104,6 +104,28 @@ async function generateHighBitrateVideo () { | |||
104 | return tempFixturePath | 104 | return tempFixturePath |
105 | } | 105 | } |
106 | 106 | ||
107 | async function generateVideoWithFramerate (fps = 60) { | ||
108 | const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true) | ||
109 | |||
110 | await ensureDir(dirname(tempFixturePath)) | ||
111 | |||
112 | const exists = await pathExists(tempFixturePath) | ||
113 | if (!exists) { | ||
114 | return new Promise<string>((res, rej) => { | ||
115 | ffmpeg() | ||
116 | .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ]) | ||
117 | .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) | ||
118 | .outputOptions([ `-r ${fps}` ]) | ||
119 | .output(tempFixturePath) | ||
120 | .on('error', rej) | ||
121 | .on('end', () => res(tempFixturePath)) | ||
122 | .run() | ||
123 | }) | ||
124 | } | ||
125 | |||
126 | return tempFixturePath | ||
127 | } | ||
128 | |||
107 | // --------------------------------------------------------------------------- | 129 | // --------------------------------------------------------------------------- |
108 | 130 | ||
109 | export { | 131 | export { |
@@ -115,5 +137,6 @@ export { | |||
115 | testImage, | 137 | testImage, |
116 | buildAbsoluteFixturePath, | 138 | buildAbsoluteFixturePath, |
117 | root, | 139 | root, |
118 | generateHighBitrateVideo | 140 | generateHighBitrateVideo, |
141 | generateVideoWithFramerate | ||
119 | } | 142 | } |
diff --git a/shared/extra-utils/miscs/sql.ts b/shared/extra-utils/miscs/sql.ts index 167649c6d..5bd5d5d8a 100644 --- a/shared/extra-utils/miscs/sql.ts +++ b/shared/extra-utils/miscs/sql.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { QueryTypes, Sequelize } from 'sequelize' | 1 | import { QueryTypes, Sequelize } from 'sequelize' |
2 | import { ServerInfo } from '../server/servers' | 2 | import { ServerInfo } from '../server/servers' |
3 | 3 | ||
4 | let sequelizes: { [ id: number ]: Sequelize } = {} | 4 | const sequelizes: { [ id: number ]: Sequelize } = {} |
5 | 5 | ||
6 | function getSequelize (internalServerNumber: number) { | 6 | function getSequelize (internalServerNumber: number) { |
7 | if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber] | 7 | if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber] |
@@ -52,22 +52,23 @@ async function countVideoViewsOf (internalServerNumber: number, uuid: string) { | |||
52 | const seq = getSequelize(internalServerNumber) | 52 | const seq = getSequelize(internalServerNumber) |
53 | 53 | ||
54 | // tslint:disable | 54 | // tslint:disable |
55 | 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" ' + |
56 | `INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'` | ||
56 | 57 | ||
57 | const options = { type: QueryTypes.SELECT as QueryTypes.SELECT } | 58 | const options = { type: QueryTypes.SELECT as QueryTypes.SELECT } |
58 | const [ { total } ] = await seq.query<{ total: number }>(query, options) | 59 | const [ { total } ] = await seq.query<{ total: number }>(query, options) |
59 | 60 | ||
60 | if (!total) return 0 | 61 | if (!total) return 0 |
61 | 62 | ||
62 | // FIXME: check if we really need parseInt | ||
63 | return parseInt(total + '', 10) | 63 | return parseInt(total + '', 10) |
64 | } | 64 | } |
65 | 65 | ||
66 | async function closeAllSequelize (servers: ServerInfo[]) { | 66 | async function closeAllSequelize (servers: ServerInfo[]) { |
67 | for (const server of servers) { | 67 | for (const server of servers) { |
68 | if (sequelizes[ server.internalServerNumber ]) { | 68 | if (sequelizes[server.internalServerNumber]) { |
69 | await sequelizes[ server.internalServerNumber ].close() | 69 | await sequelizes[server.internalServerNumber].close() |
70 | delete sequelizes[ server.internalServerNumber ] | 70 | // eslint-disable-next-line |
71 | delete sequelizes[server.internalServerNumber] | ||
71 | } | 72 | } |
72 | } | 73 | } |
73 | } | 74 | } |
diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index 3532fb429..61167f212 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts | |||
@@ -1,25 +1,27 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ | ||
2 | |||
1 | import * as request from 'supertest' | 3 | import * as request from 'supertest' |
2 | import { buildAbsoluteFixturePath, root } from '../miscs/miscs' | 4 | import { buildAbsoluteFixturePath, root } from '../miscs/miscs' |
3 | import { isAbsolute, join } from 'path' | 5 | import { isAbsolute, join } from 'path' |
4 | import { parse } from 'url' | 6 | import { URL } from 'url' |
5 | 7 | ||
6 | function get4KFileUrl () { | 8 | function get4KFileUrl () { |
7 | return 'https://download.cpy.re/peertube/4k_file.txt' | 9 | return 'https://download.cpy.re/peertube/4k_file.txt' |
8 | } | 10 | } |
9 | 11 | ||
10 | function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) { | 12 | function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) { |
11 | const { host, protocol, pathname } = parse(url) | 13 | const { host, protocol, pathname } = new URL(url) |
12 | 14 | ||
13 | return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range }) | 15 | return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range }) |
14 | } | 16 | } |
15 | 17 | ||
16 | function makeGetRequest (options: { | 18 | function makeGetRequest (options: { |
17 | url: string, | 19 | url: string |
18 | path?: string, | 20 | path?: string |
19 | query?: any, | 21 | query?: any |
20 | token?: string, | 22 | token?: string |
21 | statusCodeExpected?: number, | 23 | statusCodeExpected?: number |
22 | contentType?: string, | 24 | contentType?: string |
23 | range?: string | 25 | range?: string |
24 | }) { | 26 | }) { |
25 | if (!options.statusCodeExpected) options.statusCodeExpected = 400 | 27 | if (!options.statusCodeExpected) options.statusCodeExpected = 400 |
@@ -36,9 +38,9 @@ function makeGetRequest (options: { | |||
36 | } | 38 | } |
37 | 39 | ||
38 | function makeDeleteRequest (options: { | 40 | function makeDeleteRequest (options: { |
39 | url: string, | 41 | url: string |
40 | path: string, | 42 | path: string |
41 | token?: string, | 43 | token?: string |
42 | statusCodeExpected?: number | 44 | statusCodeExpected?: number |
43 | }) { | 45 | }) { |
44 | if (!options.statusCodeExpected) options.statusCodeExpected = 400 | 46 | if (!options.statusCodeExpected) options.statusCodeExpected = 400 |
@@ -53,12 +55,12 @@ function makeDeleteRequest (options: { | |||
53 | } | 55 | } |
54 | 56 | ||
55 | function makeUploadRequest (options: { | 57 | function makeUploadRequest (options: { |
56 | url: string, | 58 | url: string |
57 | method?: 'POST' | 'PUT', | 59 | method?: 'POST' | 'PUT' |
58 | path: string, | 60 | path: string |
59 | token?: string, | 61 | token?: string |
60 | fields: { [ fieldName: string ]: any }, | 62 | fields: { [ fieldName: string ]: any } |
61 | attaches: { [ attachName: string ]: any | any[] }, | 63 | attaches: { [ attachName: string ]: any | any[] } |
62 | statusCodeExpected?: number | 64 | statusCodeExpected?: number |
63 | }) { | 65 | }) { |
64 | if (!options.statusCodeExpected) options.statusCodeExpected = 400 | 66 | if (!options.statusCodeExpected) options.statusCodeExpected = 400 |
@@ -101,10 +103,10 @@ function makeUploadRequest (options: { | |||
101 | } | 103 | } |
102 | 104 | ||
103 | function makePostBodyRequest (options: { | 105 | function makePostBodyRequest (options: { |
104 | url: string, | 106 | url: string |
105 | path: string, | 107 | path: string |
106 | token?: string, | 108 | token?: string |
107 | fields?: { [ fieldName: string ]: any }, | 109 | fields?: { [ fieldName: string ]: any } |
108 | statusCodeExpected?: number | 110 | statusCodeExpected?: number |
109 | }) { | 111 | }) { |
110 | if (!options.fields) options.fields = {} | 112 | if (!options.fields) options.fields = {} |
@@ -121,10 +123,10 @@ function makePostBodyRequest (options: { | |||
121 | } | 123 | } |
122 | 124 | ||
123 | function makePutBodyRequest (options: { | 125 | function makePutBodyRequest (options: { |
124 | url: string, | 126 | url: string |
125 | path: string, | 127 | path: string |
126 | token?: string, | 128 | token?: string |
127 | fields: { [ fieldName: string ]: any }, | 129 | fields: { [ fieldName: string ]: any } |
128 | statusCodeExpected?: number | 130 | statusCodeExpected?: number |
129 | }) { | 131 | }) { |
130 | if (!options.statusCodeExpected) options.statusCodeExpected = 400 | 132 | if (!options.statusCodeExpected) options.statusCodeExpected = 400 |
@@ -147,9 +149,9 @@ function makeHTMLRequest (url: string, path: string) { | |||
147 | } | 149 | } |
148 | 150 | ||
149 | function updateAvatarRequest (options: { | 151 | function updateAvatarRequest (options: { |
150 | url: string, | 152 | url: string |
151 | path: string, | 153 | path: string |
152 | accessToken: string, | 154 | accessToken: string |
153 | fixture: string | 155 | fixture: string |
154 | }) { | 156 | }) { |
155 | let filePath = '' | 157 | let filePath = '' |
diff --git a/shared/extra-utils/search/videos.ts b/shared/extra-utils/search/videos.ts index da806e692..4c52ea11c 100644 --- a/shared/extra-utils/search/videos.ts +++ b/shared/extra-utils/search/videos.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as request from 'supertest' | 3 | import * as request from 'supertest' |
4 | import { VideosSearchQuery } from '../../models/search' | 4 | import { VideosSearchQuery } from '../../models/search' |
diff --git a/shared/extra-utils/server/clients.ts b/shared/extra-utils/server/clients.ts index 273aac747..dc631e823 100644 --- a/shared/extra-utils/server/clients.ts +++ b/shared/extra-utils/server/clients.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import * as request from 'supertest' | 1 | import * as request from 'supertest' |
2 | import * as urlUtil from 'url' | 2 | import { URL } from 'url' |
3 | 3 | ||
4 | function getClient (url: string) { | 4 | function getClient (url: string) { |
5 | const path = '/api/v1/oauth-clients/local' | 5 | const path = '/api/v1/oauth-clients/local' |
6 | 6 | ||
7 | return request(url) | 7 | return request(url) |
8 | .get(path) | 8 | .get(path) |
9 | .set('Host', urlUtil.parse(url).host) | 9 | .set('Host', new URL(url).host) |
10 | .set('Accept', 'application/json') | 10 | .set('Accept', 'application/json') |
11 | .expect(200) | 11 | .expect(200) |
12 | .expect('Content-Type', /json/) | 12 | .expect('Content-Type', /json/) |
diff --git a/shared/extra-utils/server/contact-form.ts b/shared/extra-utils/server/contact-form.ts index e002e03dd..d50f83241 100644 --- a/shared/extra-utils/server/contact-form.ts +++ b/shared/extra-utils/server/contact-form.ts | |||
@@ -2,11 +2,11 @@ import * as request from 'supertest' | |||
2 | import { ContactForm } from '../../models/server' | 2 | import { ContactForm } from '../../models/server' |
3 | 3 | ||
4 | function sendContactForm (options: { | 4 | function sendContactForm (options: { |
5 | url: string, | 5 | url: string |
6 | fromEmail: string, | 6 | fromEmail: string |
7 | fromName: string, | 7 | fromName: string |
8 | subject: string, | 8 | subject: string |
9 | body: string, | 9 | body: string |
10 | expectedStatus?: number | 10 | expectedStatus?: number |
11 | }) { | 11 | }) { |
12 | const path = '/api/v1/server/contact' | 12 | const path = '/api/v1/server/contact' |
diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts index 3f7729c20..006d59199 100644 --- a/shared/extra-utils/server/follows.ts +++ b/shared/extra-utils/server/follows.ts | |||
@@ -5,12 +5,12 @@ import { makePostBodyRequest } from '../requests/requests' | |||
5 | import { ActivityPubActorType, FollowState } from '@shared/models' | 5 | import { ActivityPubActorType, FollowState } from '@shared/models' |
6 | 6 | ||
7 | function getFollowersListPaginationAndSort (options: { | 7 | function getFollowersListPaginationAndSort (options: { |
8 | url: string, | 8 | url: string |
9 | start: number, | 9 | start: number |
10 | count: number, | 10 | count: number |
11 | sort: string, | 11 | sort: string |
12 | search?: string, | 12 | search?: string |
13 | actorType?: ActivityPubActorType, | 13 | actorType?: ActivityPubActorType |
14 | state?: FollowState | 14 | state?: FollowState |
15 | }) { | 15 | }) { |
16 | const { url, start, count, sort, search, state, actorType } = options | 16 | const { url, start, count, sort, search, state, actorType } = options |
@@ -56,12 +56,12 @@ function rejectFollower (url: string, token: string, follower: string, statusCod | |||
56 | } | 56 | } |
57 | 57 | ||
58 | function getFollowingListPaginationAndSort (options: { | 58 | function getFollowingListPaginationAndSort (options: { |
59 | url: string, | 59 | url: string |
60 | start: number, | 60 | start: number |
61 | count: number, | 61 | count: number |
62 | sort: string, | 62 | sort: string |
63 | search?: string, | 63 | search?: string |
64 | actorType?: ActivityPubActorType, | 64 | actorType?: ActivityPubActorType |
65 | state?: FollowState | 65 | state?: FollowState |
66 | }) { | 66 | }) { |
67 | const { url, start, count, sort, search, state, actorType } = options | 67 | const { url, start, count, sort, search, state, actorType } = options |
@@ -92,7 +92,7 @@ function follow (follower: string, following: string[], accessToken: string, exp | |||
92 | .post(path) | 92 | .post(path) |
93 | .set('Accept', 'application/json') | 93 | .set('Accept', 'application/json') |
94 | .set('Authorization', 'Bearer ' + accessToken) | 94 | .set('Authorization', 'Bearer ' + accessToken) |
95 | .send({ 'hosts': followingHosts }) | 95 | .send({ hosts: followingHosts }) |
96 | .expect(expectedStatus) | 96 | .expect(expectedStatus) |
97 | } | 97 | } |
98 | 98 | ||
diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts index 56fe5fa2a..d984b3d1e 100644 --- a/shared/extra-utils/server/jobs.ts +++ b/shared/extra-utils/server/jobs.ts | |||
@@ -8,20 +8,20 @@ function getJobsList (url: string, accessToken: string, state: JobState) { | |||
8 | const path = '/api/v1/jobs/' + state | 8 | const path = '/api/v1/jobs/' + state |
9 | 9 | ||
10 | return request(url) | 10 | return request(url) |
11 | .get(path) | 11 | .get(path) |
12 | .set('Accept', 'application/json') | 12 | .set('Accept', 'application/json') |
13 | .set('Authorization', 'Bearer ' + accessToken) | 13 | .set('Authorization', 'Bearer ' + accessToken) |
14 | .expect(200) | 14 | .expect(200) |
15 | .expect('Content-Type', /json/) | 15 | .expect('Content-Type', /json/) |
16 | } | 16 | } |
17 | 17 | ||
18 | function getJobsListPaginationAndSort (options: { | 18 | function getJobsListPaginationAndSort (options: { |
19 | url: string, | 19 | url: string |
20 | accessToken: string, | 20 | accessToken: string |
21 | state: JobState, | 21 | state: JobState |
22 | start: number, | 22 | start: number |
23 | count: number, | 23 | count: number |
24 | sort: string, | 24 | sort: string |
25 | jobType?: JobType | 25 | jobType?: JobType |
26 | }) { | 26 | }) { |
27 | const { url, accessToken, state, start, count, sort, jobType } = options | 27 | const { url, accessToken, state, start, count, sort, jobType } = options |
diff --git a/shared/extra-utils/server/plugins.ts b/shared/extra-utils/server/plugins.ts index 5c0d1e511..2d02d823d 100644 --- a/shared/extra-utils/server/plugins.ts +++ b/shared/extra-utils/server/plugins.ts | |||
@@ -7,13 +7,13 @@ import { root } from '../miscs/miscs' | |||
7 | import { join } from 'path' | 7 | import { join } from 'path' |
8 | 8 | ||
9 | function listPlugins (parameters: { | 9 | function listPlugins (parameters: { |
10 | url: string, | 10 | url: string |
11 | accessToken: string, | 11 | accessToken: string |
12 | start?: number, | 12 | start?: number |
13 | count?: number, | 13 | count?: number |
14 | sort?: string, | 14 | sort?: string |
15 | pluginType?: PluginType, | 15 | pluginType?: PluginType |
16 | uninstalled?: boolean, | 16 | uninstalled?: boolean |
17 | expectedStatus?: number | 17 | expectedStatus?: number |
18 | }) { | 18 | }) { |
19 | const { url, accessToken, start, count, sort, pluginType, uninstalled, expectedStatus = 200 } = parameters | 19 | const { url, accessToken, start, count, sort, pluginType, uninstalled, expectedStatus = 200 } = parameters |
@@ -35,13 +35,13 @@ function listPlugins (parameters: { | |||
35 | } | 35 | } |
36 | 36 | ||
37 | function listAvailablePlugins (parameters: { | 37 | function listAvailablePlugins (parameters: { |
38 | url: string, | 38 | url: string |
39 | accessToken: string, | 39 | accessToken: string |
40 | start?: number, | 40 | start?: number |
41 | count?: number, | 41 | count?: number |
42 | sort?: string, | 42 | sort?: string |
43 | pluginType?: PluginType, | 43 | pluginType?: PluginType |
44 | currentPeerTubeEngine?: string, | 44 | currentPeerTubeEngine?: string |
45 | search?: string | 45 | search?: string |
46 | expectedStatus?: number | 46 | expectedStatus?: number |
47 | }) { | 47 | }) { |
@@ -67,9 +67,9 @@ function listAvailablePlugins (parameters: { | |||
67 | } | 67 | } |
68 | 68 | ||
69 | function getPlugin (parameters: { | 69 | function getPlugin (parameters: { |
70 | url: string, | 70 | url: string |
71 | accessToken: string, | 71 | accessToken: string |
72 | npmName: string, | 72 | npmName: string |
73 | expectedStatus?: number | 73 | expectedStatus?: number |
74 | }) { | 74 | }) { |
75 | const { url, accessToken, npmName, expectedStatus = 200 } = parameters | 75 | const { url, accessToken, npmName, expectedStatus = 200 } = parameters |
@@ -84,10 +84,10 @@ function getPlugin (parameters: { | |||
84 | } | 84 | } |
85 | 85 | ||
86 | function updatePluginSettings (parameters: { | 86 | function updatePluginSettings (parameters: { |
87 | url: string, | 87 | url: string |
88 | accessToken: string, | 88 | accessToken: string |
89 | npmName: string, | 89 | npmName: string |
90 | settings: any, | 90 | settings: any |
91 | expectedStatus?: number | 91 | expectedStatus?: number |
92 | }) { | 92 | }) { |
93 | const { url, accessToken, npmName, settings, expectedStatus = 204 } = parameters | 93 | const { url, accessToken, npmName, settings, expectedStatus = 204 } = parameters |
@@ -103,9 +103,9 @@ function updatePluginSettings (parameters: { | |||
103 | } | 103 | } |
104 | 104 | ||
105 | function getPluginRegisteredSettings (parameters: { | 105 | function getPluginRegisteredSettings (parameters: { |
106 | url: string, | 106 | url: string |
107 | accessToken: string, | 107 | accessToken: string |
108 | npmName: string, | 108 | npmName: string |
109 | expectedStatus?: number | 109 | expectedStatus?: number |
110 | }) { | 110 | }) { |
111 | const { url, accessToken, npmName, expectedStatus = 200 } = parameters | 111 | const { url, accessToken, npmName, expectedStatus = 200 } = parameters |
@@ -120,8 +120,8 @@ function getPluginRegisteredSettings (parameters: { | |||
120 | } | 120 | } |
121 | 121 | ||
122 | function getPublicSettings (parameters: { | 122 | function getPublicSettings (parameters: { |
123 | url: string, | 123 | url: string |
124 | npmName: string, | 124 | npmName: string |
125 | expectedStatus?: number | 125 | expectedStatus?: number |
126 | }) { | 126 | }) { |
127 | const { url, npmName, expectedStatus = 200 } = parameters | 127 | const { url, npmName, expectedStatus = 200 } = parameters |
@@ -135,8 +135,8 @@ function getPublicSettings (parameters: { | |||
135 | } | 135 | } |
136 | 136 | ||
137 | function getPluginTranslations (parameters: { | 137 | function getPluginTranslations (parameters: { |
138 | url: string, | 138 | url: string |
139 | locale: string, | 139 | locale: string |
140 | expectedStatus?: number | 140 | expectedStatus?: number |
141 | }) { | 141 | }) { |
142 | const { url, locale, expectedStatus = 200 } = parameters | 142 | const { url, locale, expectedStatus = 200 } = parameters |
@@ -150,9 +150,9 @@ function getPluginTranslations (parameters: { | |||
150 | } | 150 | } |
151 | 151 | ||
152 | function installPlugin (parameters: { | 152 | function installPlugin (parameters: { |
153 | url: string, | 153 | url: string |
154 | accessToken: string, | 154 | accessToken: string |
155 | path?: string, | 155 | path?: string |
156 | npmName?: string | 156 | npmName?: string |
157 | expectedStatus?: number | 157 | expectedStatus?: number |
158 | }) { | 158 | }) { |
@@ -169,9 +169,9 @@ function installPlugin (parameters: { | |||
169 | } | 169 | } |
170 | 170 | ||
171 | function updatePlugin (parameters: { | 171 | function updatePlugin (parameters: { |
172 | url: string, | 172 | url: string |
173 | accessToken: string, | 173 | accessToken: string |
174 | path?: string, | 174 | path?: string |
175 | npmName?: string | 175 | npmName?: string |
176 | expectedStatus?: number | 176 | expectedStatus?: number |
177 | }) { | 177 | }) { |
@@ -188,8 +188,8 @@ function updatePlugin (parameters: { | |||
188 | } | 188 | } |
189 | 189 | ||
190 | function uninstallPlugin (parameters: { | 190 | function uninstallPlugin (parameters: { |
191 | url: string, | 191 | url: string |
192 | accessToken: string, | 192 | accessToken: string |
193 | npmName: string | 193 | npmName: string |
194 | expectedStatus?: number | 194 | expectedStatus?: number |
195 | }) { | 195 | }) { |
diff --git a/shared/extra-utils/server/redundancy.ts b/shared/extra-utils/server/redundancy.ts index c39ff2c8b..08467e4c0 100644 --- a/shared/extra-utils/server/redundancy.ts +++ b/shared/extra-utils/server/redundancy.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { makePutBodyRequest } from '../requests/requests' | 1 | import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' |
2 | import { VideoRedundanciesTarget } from '@shared/models' | ||
2 | 3 | ||
3 | async function updateRedundancy (url: string, accessToken: string, host: string, redundancyAllowed: boolean, expectedStatus = 204) { | 4 | function updateRedundancy (url: string, accessToken: string, host: string, redundancyAllowed: boolean, expectedStatus = 204) { |
4 | const path = '/api/v1/server/redundancy/' + host | 5 | const path = '/api/v1/server/redundancy/' + host |
5 | 6 | ||
6 | return makePutBodyRequest({ | 7 | return makePutBodyRequest({ |
@@ -12,6 +13,69 @@ async function updateRedundancy (url: string, accessToken: string, host: string, | |||
12 | }) | 13 | }) |
13 | } | 14 | } |
14 | 15 | ||
16 | function listVideoRedundancies (options: { | ||
17 | url: string | ||
18 | accessToken: string | ||
19 | target: VideoRedundanciesTarget | ||
20 | start?: number | ||
21 | count?: number | ||
22 | sort?: string | ||
23 | statusCodeExpected?: number | ||
24 | }) { | ||
25 | const path = '/api/v1/server/redundancy/videos' | ||
26 | |||
27 | const { url, accessToken, target, statusCodeExpected, start, count, sort } = options | ||
28 | |||
29 | return makeGetRequest({ | ||
30 | url, | ||
31 | token: accessToken, | ||
32 | path, | ||
33 | query: { | ||
34 | start: start ?? 0, | ||
35 | count: count ?? 5, | ||
36 | sort: sort ?? 'name', | ||
37 | target | ||
38 | }, | ||
39 | statusCodeExpected: statusCodeExpected || 200 | ||
40 | }) | ||
41 | } | ||
42 | |||
43 | function addVideoRedundancy (options: { | ||
44 | url: string | ||
45 | accessToken: string | ||
46 | videoId: number | ||
47 | }) { | ||
48 | const path = '/api/v1/server/redundancy/videos' | ||
49 | const { url, accessToken, videoId } = options | ||
50 | |||
51 | return makePostBodyRequest({ | ||
52 | url, | ||
53 | token: accessToken, | ||
54 | path, | ||
55 | fields: { videoId }, | ||
56 | statusCodeExpected: 204 | ||
57 | }) | ||
58 | } | ||
59 | |||
60 | function removeVideoRedundancy (options: { | ||
61 | url: string | ||
62 | accessToken: string | ||
63 | redundancyId: number | ||
64 | }) { | ||
65 | const { url, accessToken, redundancyId } = options | ||
66 | const path = '/api/v1/server/redundancy/videos/' + redundancyId | ||
67 | |||
68 | return makeDeleteRequest({ | ||
69 | url, | ||
70 | token: accessToken, | ||
71 | path, | ||
72 | statusCodeExpected: 204 | ||
73 | }) | ||
74 | } | ||
75 | |||
15 | export { | 76 | export { |
16 | updateRedundancy | 77 | updateRedundancy, |
78 | listVideoRedundancies, | ||
79 | addVideoRedundancy, | ||
80 | removeVideoRedundancy | ||
17 | } | 81 | } |
diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index a0720d778..a0f0ce9c9 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts | |||
@@ -1,16 +1,15 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ |
2 | 2 | ||
3 | import { ChildProcess, exec, fork } from 'child_process' | 3 | import { ChildProcess, exec, fork } from 'child_process' |
4 | import { join } from 'path' | 4 | import { join } from 'path' |
5 | import { root, wait } from '../miscs/miscs' | 5 | import { root, wait } from '../miscs/miscs' |
6 | import { copy, pathExists, readdir, readFile, remove } from 'fs-extra' | 6 | import { copy, pathExists, readdir, readFile, remove } from 'fs-extra' |
7 | import { existsSync } from 'fs' | ||
8 | import { expect } from 'chai' | 7 | import { expect } from 'chai' |
9 | import { VideoChannel } from '../../models/videos' | 8 | import { VideoChannel } from '../../models/videos' |
10 | import { randomInt } from '../../core-utils/miscs/miscs' | 9 | import { randomInt } from '../../core-utils/miscs/miscs' |
11 | 10 | ||
12 | interface ServerInfo { | 11 | interface ServerInfo { |
13 | app: ChildProcess, | 12 | app: ChildProcess |
14 | url: string | 13 | url: string |
15 | host: string | 14 | host: string |
16 | 15 | ||
@@ -20,13 +19,13 @@ interface ServerInfo { | |||
20 | serverNumber: number | 19 | serverNumber: number |
21 | 20 | ||
22 | client: { | 21 | client: { |
23 | id: string, | 22 | id: string |
24 | secret: string | 23 | secret: string |
25 | } | 24 | } |
26 | 25 | ||
27 | user: { | 26 | user: { |
28 | username: string, | 27 | username: string |
29 | password: string, | 28 | password: string |
30 | email?: string | 29 | email?: string |
31 | } | 30 | } |
32 | 31 | ||
@@ -57,7 +56,7 @@ function parallelTests () { | |||
57 | } | 56 | } |
58 | 57 | ||
59 | function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { | 58 | function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { |
60 | let apps = [] | 59 | const apps = [] |
61 | let i = 0 | 60 | let i = 0 |
62 | 61 | ||
63 | return new Promise<ServerInfo[]>(res => { | 62 | return new Promise<ServerInfo[]>(res => { |
@@ -203,20 +202,20 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] | |||
203 | 202 | ||
204 | // Capture things if we want to | 203 | // Capture things if we want to |
205 | for (const key of Object.keys(regexps)) { | 204 | for (const key of Object.keys(regexps)) { |
206 | const regexp = regexps[ key ] | 205 | const regexp = regexps[key] |
207 | const matches = data.toString().match(regexp) | 206 | const matches = data.toString().match(regexp) |
208 | if (matches !== null) { | 207 | if (matches !== null) { |
209 | if (key === 'client_id') server.client.id = matches[ 1 ] | 208 | if (key === 'client_id') server.client.id = matches[1] |
210 | else if (key === 'client_secret') server.client.secret = matches[ 1 ] | 209 | else if (key === 'client_secret') server.client.secret = matches[1] |
211 | else if (key === 'user_username') server.user.username = matches[ 1 ] | 210 | else if (key === 'user_username') server.user.username = matches[1] |
212 | else if (key === 'user_password') server.user.password = matches[ 1 ] | 211 | else if (key === 'user_password') server.user.password = matches[1] |
213 | } | 212 | } |
214 | } | 213 | } |
215 | 214 | ||
216 | // Check if all required sentences are here | 215 | // Check if all required sentences are here |
217 | for (const key of Object.keys(serverRunString)) { | 216 | for (const key of Object.keys(serverRunString)) { |
218 | if (data.toString().indexOf(key) !== -1) serverRunString[ key ] = true | 217 | if (data.toString().indexOf(key) !== -1) serverRunString[key] = true |
219 | if (serverRunString[ key ] === false) dontContinue = true | 218 | if (serverRunString[key] === false) dontContinue = true |
220 | } | 219 | } |
221 | 220 | ||
222 | // If no, there is maybe one thing not already initialized (client/user credentials generation...) | 221 | // If no, there is maybe one thing not already initialized (client/user credentials generation...) |
diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts index 627e17cc3..f87706f6a 100644 --- a/shared/extra-utils/users/accounts.ts +++ b/shared/extra-utils/users/accounts.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as request from 'supertest' | 3 | import * as request from 'supertest' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
diff --git a/shared/extra-utils/users/blocklist.ts b/shared/extra-utils/users/blocklist.ts index 5feb84179..39e720b42 100644 --- a/shared/extra-utils/users/blocklist.ts +++ b/shared/extra-utils/users/blocklist.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests' | 3 | import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests' |
4 | 4 | ||
diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts index f9bfb3cb3..4fe54a74a 100644 --- a/shared/extra-utils/users/login.ts +++ b/shared/extra-utils/users/login.ts | |||
@@ -60,7 +60,7 @@ function setAccessTokensToServers (servers: ServerInfo[]) { | |||
60 | const tasks: Promise<any>[] = [] | 60 | const tasks: Promise<any>[] = [] |
61 | 61 | ||
62 | for (const server of servers) { | 62 | for (const server of servers) { |
63 | const p = serverLogin(server).then(t => server.accessToken = t) | 63 | const p = serverLogin(server).then(t => { server.accessToken = t }) |
64 | tasks.push(p) | 64 | tasks.push(p) |
65 | } | 65 | } |
66 | 66 | ||
diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/user-notifications.ts index 9a5fd7e86..f949878e4 100644 --- a/shared/extra-utils/users/user-notifications.ts +++ b/shared/extra-utils/users/user-notifications.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' | 3 | import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' |
4 | import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users' | 4 | import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users' |
@@ -54,6 +54,7 @@ function markAsReadNotifications (url: string, token: string, ids: number[], sta | |||
54 | statusCodeExpected | 54 | statusCodeExpected |
55 | }) | 55 | }) |
56 | } | 56 | } |
57 | |||
57 | function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) { | 58 | function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) { |
58 | const path = '/api/v1/users/me/notifications/read-all' | 59 | const path = '/api/v1/users/me/notifications/read-all' |
59 | 60 | ||
@@ -77,7 +78,7 @@ type CheckerBaseParams = { | |||
77 | server: ServerInfo | 78 | server: ServerInfo |
78 | emails: object[] | 79 | emails: object[] |
79 | socketNotifications: UserNotification[] | 80 | socketNotifications: UserNotification[] |
80 | token: string, | 81 | token: string |
81 | check?: { web: boolean, mail: boolean } | 82 | check?: { web: boolean, mail: boolean } |
82 | } | 83 | } |
83 | 84 | ||
@@ -172,7 +173,7 @@ async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName | |||
172 | } | 173 | } |
173 | 174 | ||
174 | function emailFinder (email: object) { | 175 | function emailFinder (email: object) { |
175 | const text = email[ 'text' ] | 176 | const text = email['text'] |
176 | return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1 | 177 | return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1 |
177 | } | 178 | } |
178 | 179 | ||
@@ -195,7 +196,7 @@ async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string | |||
195 | } | 196 | } |
196 | 197 | ||
197 | function emailFinder (email: object) { | 198 | function emailFinder (email: object) { |
198 | const text: string = email[ 'text' ] | 199 | const text: string = email['text'] |
199 | return text.includes(videoUUID) && text.includes('Your video') | 200 | return text.includes(videoUUID) && text.includes('Your video') |
200 | } | 201 | } |
201 | 202 | ||
@@ -226,7 +227,7 @@ async function checkMyVideoImportIsFinished ( | |||
226 | } | 227 | } |
227 | 228 | ||
228 | function emailFinder (email: object) { | 229 | function emailFinder (email: object) { |
229 | const text: string = email[ 'text' ] | 230 | const text: string = email['text'] |
230 | const toFind = success ? ' finished' : ' error' | 231 | const toFind = success ? ' finished' : ' error' |
231 | 232 | ||
232 | return text.includes(url) && text.includes(toFind) | 233 | return text.includes(url) && text.includes(toFind) |
@@ -251,7 +252,7 @@ async function checkUserRegistered (base: CheckerBaseParams, username: string, t | |||
251 | } | 252 | } |
252 | 253 | ||
253 | function emailFinder (email: object) { | 254 | function emailFinder (email: object) { |
254 | const text: string = email[ 'text' ] | 255 | const text: string = email['text'] |
255 | 256 | ||
256 | return text.includes(' registered ') && text.includes(username) | 257 | return text.includes(' registered ') && text.includes(username) |
257 | } | 258 | } |
@@ -291,7 +292,7 @@ async function checkNewActorFollow ( | |||
291 | } | 292 | } |
292 | 293 | ||
293 | function emailFinder (email: object) { | 294 | function emailFinder (email: object) { |
294 | const text: string = email[ 'text' ] | 295 | const text: string = email['text'] |
295 | 296 | ||
296 | return text.includes('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName) | 297 | return text.includes('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName) |
297 | } | 298 | } |
@@ -320,7 +321,7 @@ async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost: | |||
320 | } | 321 | } |
321 | 322 | ||
322 | function emailFinder (email: object) { | 323 | function emailFinder (email: object) { |
323 | const text: string = email[ 'text' ] | 324 | const text: string = email['text'] |
324 | 325 | ||
325 | return text.includes('instance has a new follower') && text.includes(followerHost) | 326 | return text.includes('instance has a new follower') && text.includes(followerHost) |
326 | } | 327 | } |
@@ -351,7 +352,7 @@ async function checkAutoInstanceFollowing (base: CheckerBaseParams, followerHost | |||
351 | } | 352 | } |
352 | 353 | ||
353 | function emailFinder (email: object) { | 354 | function emailFinder (email: object) { |
354 | const text: string = email[ 'text' ] | 355 | const text: string = email['text'] |
355 | 356 | ||
356 | return text.includes(' automatically followed a new instance') && text.includes(followingHost) | 357 | return text.includes(' automatically followed a new instance') && text.includes(followingHost) |
357 | } | 358 | } |
@@ -385,7 +386,7 @@ async function checkCommentMention ( | |||
385 | } | 386 | } |
386 | 387 | ||
387 | function emailFinder (email: object) { | 388 | function emailFinder (email: object) { |
388 | const text: string = email[ 'text' ] | 389 | const text: string = email['text'] |
389 | 390 | ||
390 | return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName) | 391 | return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName) |
391 | } | 392 | } |
@@ -394,6 +395,7 @@ async function checkCommentMention ( | |||
394 | } | 395 | } |
395 | 396 | ||
396 | let lastEmailCount = 0 | 397 | let lastEmailCount = 0 |
398 | |||
397 | async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) { | 399 | async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) { |
398 | const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO | 400 | const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO |
399 | 401 | ||
@@ -413,8 +415,9 @@ async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, | |||
413 | } | 415 | } |
414 | 416 | ||
415 | const commentUrl = `http://localhost:${base.server.port}/videos/watch/${uuid};threadId=${threadId}` | 417 | const commentUrl = `http://localhost:${base.server.port}/videos/watch/${uuid};threadId=${threadId}` |
418 | |||
416 | function emailFinder (email: object) { | 419 | function emailFinder (email: object) { |
417 | return email[ 'text' ].indexOf(commentUrl) !== -1 | 420 | return email['text'].indexOf(commentUrl) !== -1 |
418 | } | 421 | } |
419 | 422 | ||
420 | await checkNotification(base, notificationChecker, emailFinder, type) | 423 | await checkNotification(base, notificationChecker, emailFinder, type) |
@@ -444,7 +447,7 @@ async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUU | |||
444 | } | 447 | } |
445 | 448 | ||
446 | function emailFinder (email: object) { | 449 | function emailFinder (email: object) { |
447 | const text = email[ 'text' ] | 450 | const text = email['text'] |
448 | return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1 | 451 | return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1 |
449 | } | 452 | } |
450 | 453 | ||
@@ -469,8 +472,8 @@ async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, vi | |||
469 | } | 472 | } |
470 | 473 | ||
471 | function emailFinder (email: object) { | 474 | function emailFinder (email: object) { |
472 | const text = email[ 'text' ] | 475 | const text = email['text'] |
473 | return text.indexOf(videoUUID) !== -1 && email[ 'text' ].indexOf('video-auto-blacklist/list') !== -1 | 476 | return text.indexOf(videoUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1 |
474 | } | 477 | } |
475 | 478 | ||
476 | await checkNotification(base, notificationChecker, emailFinder, type) | 479 | await checkNotification(base, notificationChecker, emailFinder, type) |
@@ -496,7 +499,7 @@ async function checkNewBlacklistOnMyVideo ( | |||
496 | } | 499 | } |
497 | 500 | ||
498 | function emailFinder (email: object) { | 501 | function emailFinder (email: object) { |
499 | const text = email[ 'text' ] | 502 | const text = email['text'] |
500 | return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1 | 503 | return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1 |
501 | } | 504 | } |
502 | 505 | ||
diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts index 2fe0e55c2..248af2d6e 100644 --- a/shared/extra-utils/users/users.ts +++ b/shared/extra-utils/users/users.ts | |||
@@ -9,14 +9,14 @@ import { UserUpdateMe } from '../../models/users' | |||
9 | import { omit } from 'lodash' | 9 | import { omit } from 'lodash' |
10 | 10 | ||
11 | type CreateUserArgs = { | 11 | type CreateUserArgs = { |
12 | url: string, | 12 | url: string |
13 | accessToken: string, | 13 | accessToken: string |
14 | username: string, | 14 | username: string |
15 | password: string, | 15 | password: string |
16 | videoQuota?: number, | 16 | videoQuota?: number |
17 | videoQuotaDaily?: number, | 17 | videoQuotaDaily?: number |
18 | role?: UserRole, | 18 | role?: UserRole |
19 | adminFlags?: UserAdminFlag, | 19 | adminFlags?: UserAdminFlag |
20 | specialStatus?: number | 20 | specialStatus?: number |
21 | } | 21 | } |
22 | function createUser (parameters: CreateUserArgs) { | 22 | function createUser (parameters: CreateUserArgs) { |
@@ -74,8 +74,8 @@ function registerUser (url: string, username: string, password: string, specialS | |||
74 | } | 74 | } |
75 | 75 | ||
76 | function registerUserWithChannel (options: { | 76 | function registerUserWithChannel (options: { |
77 | url: string, | 77 | url: string |
78 | user: { username: string, password: string, displayName?: string }, | 78 | user: { username: string, password: string, displayName?: string } |
79 | channel: { name: string, displayName: string } | 79 | channel: { name: string, displayName: string } |
80 | }) { | 80 | }) { |
81 | const path = '/api/v1/users/register' | 81 | const path = '/api/v1/users/register' |
@@ -230,8 +230,8 @@ function updateMyUser (options: { url: string, accessToken: string } & UserUpdat | |||
230 | } | 230 | } |
231 | 231 | ||
232 | function updateMyAvatar (options: { | 232 | function updateMyAvatar (options: { |
233 | url: string, | 233 | url: string |
234 | accessToken: string, | 234 | accessToken: string |
235 | fixture: string | 235 | fixture: string |
236 | }) { | 236 | }) { |
237 | const path = '/api/v1/users/me/avatar/pick' | 237 | const path = '/api/v1/users/me/avatar/pick' |
@@ -241,14 +241,14 @@ function updateMyAvatar (options: { | |||
241 | 241 | ||
242 | function updateUser (options: { | 242 | function updateUser (options: { |
243 | url: string | 243 | url: string |
244 | userId: number, | 244 | userId: number |
245 | accessToken: string, | 245 | accessToken: string |
246 | email?: string, | 246 | email?: string |
247 | emailVerified?: boolean, | 247 | emailVerified?: boolean |
248 | videoQuota?: number, | 248 | videoQuota?: number |
249 | videoQuotaDaily?: number, | 249 | videoQuotaDaily?: number |
250 | password?: string, | 250 | password?: string |
251 | adminFlags?: UserAdminFlag, | 251 | adminFlags?: UserAdminFlag |
252 | role?: UserRole | 252 | role?: UserRole |
253 | }) { | 253 | }) { |
254 | const path = '/api/v1/users/' + options.userId | 254 | const path = '/api/v1/users/' + options.userId |
diff --git a/shared/extra-utils/videos/video-blacklist.ts b/shared/extra-utils/videos/video-blacklist.ts index e25a292fc..ba139ef95 100644 --- a/shared/extra-utils/videos/video-blacklist.ts +++ b/shared/extra-utils/videos/video-blacklist.ts | |||
@@ -13,11 +13,11 @@ function addVideoToBlacklist ( | |||
13 | const path = '/api/v1/videos/' + videoId + '/blacklist' | 13 | const path = '/api/v1/videos/' + videoId + '/blacklist' |
14 | 14 | ||
15 | return request(url) | 15 | return request(url) |
16 | .post(path) | 16 | .post(path) |
17 | .send({ reason, unfederate }) | 17 | .send({ reason, unfederate }) |
18 | .set('Accept', 'application/json') | 18 | .set('Accept', 'application/json') |
19 | .set('Authorization', 'Bearer ' + token) | 19 | .set('Authorization', 'Bearer ' + token) |
20 | .expect(specialStatus) | 20 | .expect(specialStatus) |
21 | } | 21 | } |
22 | 22 | ||
23 | function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) { | 23 | function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) { |
@@ -35,20 +35,20 @@ function removeVideoFromBlacklist (url: string, token: string, videoId: number | | |||
35 | const path = '/api/v1/videos/' + videoId + '/blacklist' | 35 | const path = '/api/v1/videos/' + videoId + '/blacklist' |
36 | 36 | ||
37 | return request(url) | 37 | return request(url) |
38 | .delete(path) | 38 | .delete(path) |
39 | .set('Accept', 'application/json') | 39 | .set('Accept', 'application/json') |
40 | .set('Authorization', 'Bearer ' + token) | 40 | .set('Authorization', 'Bearer ' + token) |
41 | .expect(specialStatus) | 41 | .expect(specialStatus) |
42 | } | 42 | } |
43 | 43 | ||
44 | function getBlacklistedVideosList (parameters: { | 44 | function getBlacklistedVideosList (parameters: { |
45 | url: string, | 45 | url: string |
46 | token: string, | 46 | token: string |
47 | sort?: string, | 47 | sort?: string |
48 | type?: VideoBlacklistType, | 48 | type?: VideoBlacklistType |
49 | specialStatus?: number | 49 | specialStatus?: number |
50 | }) { | 50 | }) { |
51 | let { url, token, sort, type, specialStatus = 200 } = parameters | 51 | const { url, token, sort, type, specialStatus = 200 } = parameters |
52 | const path = '/api/v1/videos/blacklist/' | 52 | const path = '/api/v1/videos/blacklist/' |
53 | 53 | ||
54 | const query = { sort, type } | 54 | const query = { sort, type } |
diff --git a/shared/extra-utils/videos/video-captions.ts b/shared/extra-utils/videos/video-captions.ts index 8d67f617b..5bd533bba 100644 --- a/shared/extra-utils/videos/video-captions.ts +++ b/shared/extra-utils/videos/video-captions.ts | |||
@@ -6,12 +6,12 @@ import { buildAbsoluteFixturePath } from '../miscs/miscs' | |||
6 | const expect = chai.expect | 6 | const expect = chai.expect |
7 | 7 | ||
8 | function createVideoCaption (args: { | 8 | function createVideoCaption (args: { |
9 | url: string, | 9 | url: string |
10 | accessToken: string | 10 | accessToken: string |
11 | videoId: string | number | 11 | videoId: string | number |
12 | language: string | 12 | language: string |
13 | fixture: string, | 13 | fixture: string |
14 | mimeType?: string, | 14 | mimeType?: string |
15 | statusCodeExpected?: number | 15 | statusCodeExpected?: number |
16 | }) { | 16 | }) { |
17 | const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language | 17 | const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language |
diff --git a/shared/extra-utils/videos/video-channels.ts b/shared/extra-utils/videos/video-channels.ts index 053842331..51d433940 100644 --- a/shared/extra-utils/videos/video-channels.ts +++ b/shared/extra-utils/videos/video-channels.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-floating-promises */ | ||
2 | |||
1 | import * as request from 'supertest' | 3 | import * as request from 'supertest' |
2 | import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' | 4 | import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' |
3 | import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' | 5 | import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' |
@@ -22,11 +24,11 @@ function getVideoChannelsList (url: string, start: number, count: number, sort?: | |||
22 | } | 24 | } |
23 | 25 | ||
24 | function getAccountVideoChannelsList (parameters: { | 26 | function getAccountVideoChannelsList (parameters: { |
25 | url: string, | 27 | url: string |
26 | accountName: string, | 28 | accountName: string |
27 | start?: number, | 29 | start?: number |
28 | count?: number, | 30 | count?: number |
29 | sort?: string, | 31 | sort?: string |
30 | specialStatus?: number | 32 | specialStatus?: number |
31 | }) { | 33 | }) { |
32 | const { url, accountName, start, count, sort = 'createdAt', specialStatus = 200 } = parameters | 34 | const { url, accountName, start, count, sort = 'createdAt', specialStatus = 200 } = parameters |
@@ -113,9 +115,9 @@ function getVideoChannel (url: string, channelName: string) { | |||
113 | } | 115 | } |
114 | 116 | ||
115 | function updateVideoChannelAvatar (options: { | 117 | function updateVideoChannelAvatar (options: { |
116 | url: string, | 118 | url: string |
117 | accessToken: string, | 119 | accessToken: string |
118 | fixture: string, | 120 | fixture: string |
119 | videoChannelName: string | number | 121 | videoChannelName: string | number |
120 | }) { | 122 | }) { |
121 | 123 | ||
@@ -129,7 +131,7 @@ function setDefaultVideoChannel (servers: ServerInfo[]) { | |||
129 | 131 | ||
130 | for (const server of servers) { | 132 | for (const server of servers) { |
131 | const p = getMyUserInformation(server.url, server.accessToken) | 133 | const p = getMyUserInformation(server.url, server.accessToken) |
132 | .then(res => server.videoChannel = (res.body as User).videoChannels[0]) | 134 | .then(res => { server.videoChannel = (res.body as User).videoChannels[0] }) |
133 | 135 | ||
134 | tasks.push(p) | 136 | tasks.push(p) |
135 | } | 137 | } |
diff --git a/shared/extra-utils/videos/video-comments.ts b/shared/extra-utils/videos/video-comments.ts index 0ebf69ced..81c48412d 100644 --- a/shared/extra-utils/videos/video-comments.ts +++ b/shared/extra-utils/videos/video-comments.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-floating-promises */ | ||
2 | |||
1 | import * as request from 'supertest' | 3 | import * as request from 'supertest' |
2 | import { makeDeleteRequest } from '../requests/requests' | 4 | import { makeDeleteRequest } from '../requests/requests' |
3 | 5 | ||
diff --git a/shared/extra-utils/videos/video-imports.ts b/shared/extra-utils/videos/video-imports.ts index 150cc94ed..8e5abd2f5 100644 --- a/shared/extra-utils/videos/video-imports.ts +++ b/shared/extra-utils/videos/video-imports.ts | |||
@@ -7,7 +7,7 @@ function getYoutubeVideoUrl () { | |||
7 | } | 7 | } |
8 | 8 | ||
9 | function getMagnetURI () { | 9 | function getMagnetURI () { |
10 | // tslint:disable:max-line-length | 10 | // eslint-disable-next-line max-len |
11 | return 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4' | 11 | return 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4' |
12 | } | 12 | } |
13 | 13 | ||
diff --git a/shared/extra-utils/videos/video-playlists.ts b/shared/extra-utils/videos/video-playlists.ts index 6762c5973..5bcc02570 100644 --- a/shared/extra-utils/videos/video-playlists.ts +++ b/shared/extra-utils/videos/video-playlists.ts | |||
@@ -123,9 +123,9 @@ function deleteVideoPlaylist (url: string, token: string, playlistId: number | s | |||
123 | } | 123 | } |
124 | 124 | ||
125 | function createVideoPlaylist (options: { | 125 | function createVideoPlaylist (options: { |
126 | url: string, | 126 | url: string |
127 | token: string, | 127 | token: string |
128 | playlistAttrs: VideoPlaylistCreate, | 128 | playlistAttrs: VideoPlaylistCreate |
129 | expectedStatus?: number | 129 | expectedStatus?: number |
130 | }) { | 130 | }) { |
131 | const path = '/api/v1/video-playlists' | 131 | const path = '/api/v1/video-playlists' |
@@ -148,10 +148,10 @@ function createVideoPlaylist (options: { | |||
148 | } | 148 | } |
149 | 149 | ||
150 | function updateVideoPlaylist (options: { | 150 | function updateVideoPlaylist (options: { |
151 | url: string, | 151 | url: string |
152 | token: string, | 152 | token: string |
153 | playlistAttrs: VideoPlaylistUpdate, | 153 | playlistAttrs: VideoPlaylistUpdate |
154 | playlistId: number | string, | 154 | playlistId: number | string |
155 | expectedStatus?: number | 155 | expectedStatus?: number |
156 | }) { | 156 | }) { |
157 | const path = '/api/v1/video-playlists/' + options.playlistId | 157 | const path = '/api/v1/video-playlists/' + options.playlistId |
@@ -174,9 +174,9 @@ function updateVideoPlaylist (options: { | |||
174 | } | 174 | } |
175 | 175 | ||
176 | async function addVideoInPlaylist (options: { | 176 | async function addVideoInPlaylist (options: { |
177 | url: string, | 177 | url: string |
178 | token: string, | 178 | token: string |
179 | playlistId: number | string, | 179 | playlistId: number | string |
180 | elementAttrs: VideoPlaylistElementCreate | { videoId: string } | 180 | elementAttrs: VideoPlaylistElementCreate | { videoId: string } |
181 | expectedStatus?: number | 181 | expectedStatus?: number |
182 | }) { | 182 | }) { |
@@ -194,11 +194,11 @@ async function addVideoInPlaylist (options: { | |||
194 | } | 194 | } |
195 | 195 | ||
196 | function updateVideoPlaylistElement (options: { | 196 | function updateVideoPlaylistElement (options: { |
197 | url: string, | 197 | url: string |
198 | token: string, | 198 | token: string |
199 | playlistId: number | string, | 199 | playlistId: number | string |
200 | playlistElementId: number | string, | 200 | playlistElementId: number | string |
201 | elementAttrs: VideoPlaylistElementUpdate, | 201 | elementAttrs: VideoPlaylistElementUpdate |
202 | expectedStatus?: number | 202 | expectedStatus?: number |
203 | }) { | 203 | }) { |
204 | const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId | 204 | const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId |
@@ -213,10 +213,10 @@ function updateVideoPlaylistElement (options: { | |||
213 | } | 213 | } |
214 | 214 | ||
215 | function removeVideoFromPlaylist (options: { | 215 | function removeVideoFromPlaylist (options: { |
216 | url: string, | 216 | url: string |
217 | token: string, | 217 | token: string |
218 | playlistId: number | string, | 218 | playlistId: number | string |
219 | playlistElementId: number, | 219 | playlistElementId: number |
220 | expectedStatus?: number | 220 | expectedStatus?: number |
221 | }) { | 221 | }) { |
222 | const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId | 222 | const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId |
@@ -230,14 +230,14 @@ function removeVideoFromPlaylist (options: { | |||
230 | } | 230 | } |
231 | 231 | ||
232 | function reorderVideosPlaylist (options: { | 232 | function reorderVideosPlaylist (options: { |
233 | url: string, | 233 | url: string |
234 | token: string, | 234 | token: string |
235 | playlistId: number | string, | 235 | playlistId: number | string |
236 | elementAttrs: { | 236 | elementAttrs: { |
237 | startPosition: number, | 237 | startPosition: number |
238 | insertAfterPosition: number, | 238 | insertAfterPosition: number |
239 | reorderLength?: number | 239 | reorderLength?: number |
240 | }, | 240 | } |
241 | expectedStatus?: number | 241 | expectedStatus?: number |
242 | }) { | 242 | }) { |
243 | const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder' | 243 | const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder' |
diff --git a/shared/extra-utils/videos/video-streaming-playlists.ts b/shared/extra-utils/videos/video-streaming-playlists.ts index eb25011cb..e54da84aa 100644 --- a/shared/extra-utils/videos/video-streaming-playlists.ts +++ b/shared/extra-utils/videos/video-streaming-playlists.ts | |||
@@ -37,7 +37,7 @@ async function checkSegmentHash ( | |||
37 | 37 | ||
38 | const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url) | 38 | const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url) |
39 | 39 | ||
40 | const sha256Server = resSha.body[ videoName ][range] | 40 | const sha256Server = resSha.body[videoName][range] |
41 | expect(sha256(res2.body)).to.equal(sha256Server) | 41 | expect(sha256(res2.body)).to.equal(sha256Server) |
42 | } | 42 | } |
43 | 43 | ||
diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index 7a77a03ad..39a06b0d7 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ |
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { pathExists, readdir, readFile } from 'fs-extra' | 4 | import { pathExists, readdir, readFile } from 'fs-extra' |
@@ -488,7 +488,7 @@ async function completeVideoCheck ( | |||
488 | description: string | 488 | description: string |
489 | publishedAt?: string | 489 | publishedAt?: string |
490 | support: string | 490 | support: string |
491 | originallyPublishedAt?: string, | 491 | originallyPublishedAt?: string |
492 | account: { | 492 | account: { |
493 | name: string | 493 | name: string |
494 | host: string | 494 | host: string |
@@ -509,7 +509,7 @@ async function completeVideoCheck ( | |||
509 | files: { | 509 | files: { |
510 | resolution: number | 510 | resolution: number |
511 | size: number | 511 | size: number |
512 | }[], | 512 | }[] |
513 | thumbnailfile?: string | 513 | thumbnailfile?: string |
514 | previewfile?: string | 514 | previewfile?: string |
515 | } | 515 | } |
@@ -583,9 +583,10 @@ async function completeVideoCheck ( | |||
583 | 583 | ||
584 | const minSize = attributeFile.size - ((10 * attributeFile.size) / 100) | 584 | const minSize = attributeFile.size - ((10 * attributeFile.size) / 100) |
585 | const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100) | 585 | const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100) |
586 | expect(file.size, | 586 | expect( |
587 | 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')') | 587 | file.size, |
588 | .to.be.above(minSize).and.below(maxSize) | 588 | 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')' |
589 | ).to.be.above(minSize).and.below(maxSize) | ||
589 | 590 | ||
590 | const torrent = await webtorrentAdd(file.magnetUri, true) | 591 | const torrent = await webtorrentAdd(file.magnetUri, true) |
591 | expect(torrent.files).to.be.an('array') | 592 | expect(torrent.files).to.be.an('array') |
@@ -607,15 +608,28 @@ async function videoUUIDToId (url: string, id: number | string) { | |||
607 | return res.body.id | 608 | return res.body.id |
608 | } | 609 | } |
609 | 610 | ||
610 | async function uploadVideoAndGetId (options: { server: ServerInfo, videoName: string, nsfw?: boolean, token?: string }) { | 611 | async function uploadVideoAndGetId (options: { |
612 | server: ServerInfo | ||
613 | videoName: string | ||
614 | nsfw?: boolean | ||
615 | privacy?: VideoPrivacy | ||
616 | token?: string | ||
617 | }) { | ||
611 | const videoAttrs: any = { name: options.videoName } | 618 | const videoAttrs: any = { name: options.videoName } |
612 | if (options.nsfw) videoAttrs.nsfw = options.nsfw | 619 | if (options.nsfw) videoAttrs.nsfw = options.nsfw |
620 | if (options.privacy) videoAttrs.privacy = options.privacy | ||
613 | 621 | ||
614 | const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs) | 622 | const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs) |
615 | 623 | ||
616 | return { id: res.body.video.id, uuid: res.body.video.uuid } | 624 | return { id: res.body.video.id, uuid: res.body.video.uuid } |
617 | } | 625 | } |
618 | 626 | ||
627 | async function getLocalIdByUUID (url: string, uuid: string) { | ||
628 | const res = await getVideo(url, uuid) | ||
629 | |||
630 | return res.body.id | ||
631 | } | ||
632 | |||
619 | // --------------------------------------------------------------------------- | 633 | // --------------------------------------------------------------------------- |
620 | 634 | ||
621 | export { | 635 | export { |
@@ -645,5 +659,6 @@ export { | |||
645 | completeVideoCheck, | 659 | completeVideoCheck, |
646 | checkVideoFilesWereRemoved, | 660 | checkVideoFilesWereRemoved, |
647 | getPlaylistVideos, | 661 | getPlaylistVideos, |
648 | uploadVideoAndGetId | 662 | uploadVideoAndGetId, |
663 | getLocalIdByUUID | ||
649 | } | 664 | } |
diff --git a/shared/models/activitypub/activity.ts b/shared/models/activitypub/activity.ts index 492b672c7..20ecf176c 100644 --- a/shared/models/activitypub/activity.ts +++ b/shared/models/activitypub/activity.ts | |||
@@ -8,12 +8,33 @@ import { ViewObject } from './objects/view-object' | |||
8 | import { APObject } from './objects/object.model' | 8 | import { APObject } from './objects/object.model' |
9 | import { PlaylistObject } from './objects/playlist-object' | 9 | import { PlaylistObject } from './objects/playlist-object' |
10 | 10 | ||
11 | export type Activity = ActivityCreate | ActivityUpdate | | 11 | export type Activity = |
12 | ActivityDelete | ActivityFollow | ActivityAccept | ActivityAnnounce | | 12 | ActivityCreate | |
13 | ActivityUndo | ActivityLike | ActivityReject | ActivityView | ActivityDislike | ActivityFlag | 13 | ActivityUpdate | |
14 | 14 | ActivityDelete | | |
15 | export type ActivityType = 'Create' | 'Update' | 'Delete' | 'Follow' | 'Accept' | 'Announce' | 'Undo' | 'Like' | 'Reject' | | 15 | ActivityFollow | |
16 | 'View' | 'Dislike' | 'Flag' | 16 | ActivityAccept | |
17 | ActivityAnnounce | | ||
18 | ActivityUndo | | ||
19 | ActivityLike | | ||
20 | ActivityReject | | ||
21 | ActivityView | | ||
22 | ActivityDislike | | ||
23 | ActivityFlag | ||
24 | |||
25 | export type ActivityType = | ||
26 | 'Create' | | ||
27 | 'Update' | | ||
28 | 'Delete' | | ||
29 | 'Follow' | | ||
30 | 'Accept' | | ||
31 | 'Announce' | | ||
32 | 'Undo' | | ||
33 | 'Like' | | ||
34 | 'Reject' | | ||
35 | 'View' | | ||
36 | 'Dislike' | | ||
37 | 'Flag' | ||
17 | 38 | ||
18 | export interface ActivityAudience { | 39 | export interface ActivityAudience { |
19 | to: string[] | 40 | to: string[] |
@@ -66,17 +87,17 @@ export interface ActivityAnnounce extends BaseActivity { | |||
66 | } | 87 | } |
67 | 88 | ||
68 | export interface ActivityUndo extends BaseActivity { | 89 | export interface ActivityUndo extends BaseActivity { |
69 | type: 'Undo', | 90 | type: 'Undo' |
70 | object: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce | 91 | object: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce |
71 | } | 92 | } |
72 | 93 | ||
73 | export interface ActivityLike extends BaseActivity { | 94 | export interface ActivityLike extends BaseActivity { |
74 | type: 'Like', | 95 | type: 'Like' |
75 | object: APObject | 96 | object: APObject |
76 | } | 97 | } |
77 | 98 | ||
78 | export interface ActivityView extends BaseActivity { | 99 | export interface ActivityView extends BaseActivity { |
79 | type: 'View', | 100 | type: 'View' |
80 | actor: string | 101 | actor: string |
81 | object: APObject | 102 | object: APObject |
82 | } | 103 | } |
@@ -89,7 +110,7 @@ export interface ActivityDislike extends BaseActivity { | |||
89 | } | 110 | } |
90 | 111 | ||
91 | export interface ActivityFlag extends BaseActivity { | 112 | export interface ActivityFlag extends BaseActivity { |
92 | type: 'Flag', | 113 | type: 'Flag' |
93 | content: string, | 114 | content: string |
94 | object: APObject | APObject[] | 115 | object: APObject | APObject[] |
95 | } | 116 | } |
diff --git a/shared/models/activitypub/activitypub-actor.ts b/shared/models/activitypub/activitypub-actor.ts index b8a2dc925..f022f3d02 100644 --- a/shared/models/activitypub/activitypub-actor.ts +++ b/shared/models/activitypub/activitypub-actor.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { ActivityPubAttributedTo } from './objects/common-objects' | 1 | import { ActivityIconObject, ActivityPubAttributedTo } from './objects/common-objects' |
2 | 2 | ||
3 | export type ActivityPubActorType = 'Person' | 'Application' | 'Group' | 'Service' | 'Organization' | 3 | export type ActivityPubActorType = 'Person' | 'Application' | 'Group' | 'Service' | 'Organization' |
4 | 4 | ||
@@ -27,9 +27,5 @@ export interface ActivityPubActor { | |||
27 | publicKeyPem: string | 27 | publicKeyPem: string |
28 | } | 28 | } |
29 | 29 | ||
30 | icon: { | 30 | icon: ActivityIconObject |
31 | type: 'Image' | ||
32 | mediaType: 'image/png' | ||
33 | url: string | ||
34 | } | ||
35 | } | 31 | } |
diff --git a/shared/models/activitypub/activitypub-signature.ts b/shared/models/activitypub/activitypub-signature.ts index 1d9f4b3b3..fafdc246d 100644 --- a/shared/models/activitypub/activitypub-signature.ts +++ b/shared/models/activitypub/activitypub-signature.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | export interface ActivityPubSignature { | 1 | export interface ActivityPubSignature { |
2 | type: 'GraphSignature2012' | 2 | type: string |
3 | created: Date, | 3 | created: Date |
4 | creator: string | 4 | creator: string |
5 | signatureValue: string | 5 | signatureValue: string |
6 | } | 6 | } |
diff --git a/shared/models/activitypub/objects/cache-file-object.ts b/shared/models/activitypub/objects/cache-file-object.ts index 4b0a3a724..19a817582 100644 --- a/shared/models/activitypub/objects/cache-file-object.ts +++ b/shared/models/activitypub/objects/cache-file-object.ts | |||
@@ -2,7 +2,7 @@ import { ActivityVideoUrlObject, ActivityPlaylistUrlObject } from './common-obje | |||
2 | 2 | ||
3 | export interface CacheFileObject { | 3 | export interface CacheFileObject { |
4 | id: string | 4 | id: string |
5 | type: 'CacheFile', | 5 | type: 'CacheFile' |
6 | object: string | 6 | object: string |
7 | expires: string | 7 | expires: string |
8 | url: ActivityVideoUrlObject | ActivityPlaylistUrlObject | 8 | url: ActivityVideoUrlObject | ActivityPlaylistUrlObject |
diff --git a/shared/models/activitypub/objects/common-objects.ts b/shared/models/activitypub/objects/common-objects.ts index de1116ab3..e94d05429 100644 --- a/shared/models/activitypub/objects/common-objects.ts +++ b/shared/models/activitypub/objects/common-objects.ts | |||
@@ -1,14 +1,15 @@ | |||
1 | export interface ActivityIdentifierObject { | 1 | export interface ActivityIdentifierObject { |
2 | identifier: string | 2 | identifier: string |
3 | name: string | 3 | name: string |
4 | url?: string | ||
4 | } | 5 | } |
5 | 6 | ||
6 | export interface ActivityIconObject { | 7 | export interface ActivityIconObject { |
7 | type: 'Image' | 8 | type: 'Image' |
8 | url: string | 9 | url: string |
9 | mediaType: 'image/jpeg' | 10 | mediaType: 'image/jpeg' | 'image/png' |
10 | width: number | 11 | width?: number |
11 | height: number | 12 | height?: number |
12 | } | 13 | } |
13 | 14 | ||
14 | export type ActivityVideoUrlObject = { | 15 | export type ActivityVideoUrlObject = { |
@@ -71,19 +72,21 @@ export interface ActivityMentionObject { | |||
71 | name: string | 72 | name: string |
72 | } | 73 | } |
73 | 74 | ||
74 | export type ActivityTagObject = ActivityPlaylistSegmentHashesObject | | 75 | export type ActivityTagObject = |
75 | ActivityPlaylistInfohashesObject | | 76 | ActivityPlaylistSegmentHashesObject |
76 | ActivityVideoUrlObject | | 77 | | ActivityPlaylistInfohashesObject |
77 | ActivityHashTagObject | | 78 | | ActivityVideoUrlObject |
78 | ActivityMentionObject | | 79 | | ActivityHashTagObject |
79 | ActivityBitTorrentUrlObject | | 80 | | ActivityMentionObject |
80 | ActivityMagnetUrlObject | 81 | | ActivityBitTorrentUrlObject |
82 | | ActivityMagnetUrlObject | ||
81 | 83 | ||
82 | export type ActivityUrlObject = ActivityVideoUrlObject | | 84 | export type ActivityUrlObject = |
83 | ActivityPlaylistUrlObject | | 85 | ActivityVideoUrlObject |
84 | ActivityBitTorrentUrlObject | | 86 | | ActivityPlaylistUrlObject |
85 | ActivityMagnetUrlObject | | 87 | | ActivityBitTorrentUrlObject |
86 | ActivityHtmlUrlObject | 88 | | ActivityMagnetUrlObject |
89 | | ActivityHtmlUrlObject | ||
87 | 90 | ||
88 | export interface ActivityPubAttributedTo { | 91 | export interface ActivityPubAttributedTo { |
89 | type: 'Group' | 'Person' | 92 | type: 'Group' | 'Person' |
diff --git a/shared/models/activitypub/objects/video-abuse-object.ts b/shared/models/activitypub/objects/video-abuse-object.ts index 5f1264a76..d9622b414 100644 --- a/shared/models/activitypub/objects/video-abuse-object.ts +++ b/shared/models/activitypub/objects/video-abuse-object.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export interface VideoAbuseObject { | 1 | export interface VideoAbuseObject { |
2 | type: 'Flag', | 2 | type: 'Flag' |
3 | content: string | 3 | content: string |
4 | object: string | string[] | 4 | object: string | string[] |
5 | } | 5 | } |
diff --git a/shared/models/activitypub/objects/video-torrent-object.ts b/shared/models/activitypub/objects/video-torrent-object.ts index 239822bc4..11de8fc56 100644 --- a/shared/models/activitypub/objects/video-torrent-object.ts +++ b/shared/models/activitypub/objects/video-torrent-object.ts | |||
@@ -20,8 +20,8 @@ export interface VideoTorrentObject { | |||
20 | subtitleLanguage: ActivityIdentifierObject[] | 20 | subtitleLanguage: ActivityIdentifierObject[] |
21 | views: number | 21 | views: number |
22 | sensitive: boolean | 22 | sensitive: boolean |
23 | commentsEnabled: boolean, | 23 | commentsEnabled: boolean |
24 | downloadEnabled: boolean, | 24 | downloadEnabled: boolean |
25 | waitTranscoding: boolean | 25 | waitTranscoding: boolean |
26 | state: VideoState | 26 | state: VideoState |
27 | published: string | 27 | published: string |
@@ -30,7 +30,9 @@ export interface VideoTorrentObject { | |||
30 | mediaType: 'text/markdown' | 30 | mediaType: 'text/markdown' |
31 | content: string | 31 | content: string |
32 | support: string | 32 | support: string |
33 | icon: ActivityIconObject | 33 | |
34 | icon: ActivityIconObject[] | ||
35 | |||
34 | url: ActivityUrlObject[] | 36 | url: ActivityUrlObject[] |
35 | likes: string | 37 | likes: string |
36 | dislikes: string | 38 | dislikes: string |
diff --git a/shared/models/activitypub/objects/view-object.ts b/shared/models/activitypub/objects/view-object.ts index 00348116a..4dd21ce8e 100644 --- a/shared/models/activitypub/objects/view-object.ts +++ b/shared/models/activitypub/objects/view-object.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export interface ViewObject { | 1 | export interface ViewObject { |
2 | type: 'View', | 2 | type: 'View' |
3 | actor: string | 3 | actor: string |
4 | object: string | 4 | object: string |
5 | } | 5 | } |
diff --git a/shared/models/i18n/i18n.ts b/shared/models/i18n/i18n.ts index 032944281..9ae175df9 100644 --- a/shared/models/i18n/i18n.ts +++ b/shared/models/i18n/i18n.ts | |||
@@ -56,6 +56,8 @@ export function isDefaultLocale (locale: string) { | |||
56 | } | 56 | } |
57 | 57 | ||
58 | export function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) { | 58 | export function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) { |
59 | // FIXME: remove disable rule when the client is upgraded to typescript 3.7 | ||
60 | // eslint-disable-next-line | ||
59 | return translations && translations[str] ? translations[str] : str | 61 | return translations && translations[str] ? translations[str] : str |
60 | } | 62 | } |
61 | 63 | ||
diff --git a/shared/models/nodeinfo/index.d.ts b/shared/models/nodeinfo/index.d.ts index 0a2d0492e..336cb66d2 100644 --- a/shared/models/nodeinfo/index.d.ts +++ b/shared/models/nodeinfo/index.d.ts | |||
@@ -98,7 +98,7 @@ export interface HttpNodeinfoDiasporaSoftwareNsSchema20 { | |||
98 | * The amount of users that signed in at least once in the last 30 days. | 98 | * The amount of users that signed in at least once in the last 30 days. |
99 | */ | 99 | */ |
100 | activeMonth?: number | 100 | activeMonth?: number |
101 | }; | 101 | } |
102 | /** | 102 | /** |
103 | * The amount of posts that were made by users that are registered on this server. | 103 | * The amount of posts that were made by users that are registered on this server. |
104 | */ | 104 | */ |
diff --git a/shared/models/plugins/peertube-plugin-latest-version.model.ts b/shared/models/plugins/peertube-plugin-latest-version.model.ts index dec4618fa..811a64429 100644 --- a/shared/models/plugins/peertube-plugin-latest-version.model.ts +++ b/shared/models/plugins/peertube-plugin-latest-version.model.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export interface PeertubePluginLatestVersionRequest { | 1 | export interface PeertubePluginLatestVersionRequest { |
2 | currentPeerTubeEngine?: string, | 2 | currentPeerTubeEngine?: string |
3 | 3 | ||
4 | npmNames: string[] | 4 | npmNames: string[] |
5 | } | 5 | } |
diff --git a/shared/models/plugins/plugin-package-json.model.ts b/shared/models/plugins/plugin-package-json.model.ts index 3f3077671..c26e9ae5b 100644 --- a/shared/models/plugins/plugin-package-json.model.ts +++ b/shared/models/plugins/plugin-package-json.model.ts | |||
@@ -5,7 +5,7 @@ export type PluginTranslationPaths = { | |||
5 | } | 5 | } |
6 | 6 | ||
7 | export type ClientScript = { | 7 | export type ClientScript = { |
8 | script: string, | 8 | script: string |
9 | scopes: PluginClientScope[] | 9 | scopes: PluginClientScope[] |
10 | } | 10 | } |
11 | 11 | ||
@@ -13,12 +13,12 @@ export type PluginPackageJson = { | |||
13 | name: string | 13 | name: string |
14 | version: string | 14 | version: string |
15 | description: string | 15 | description: string |
16 | engine: { peertube: string }, | 16 | engine: { peertube: string } |
17 | 17 | ||
18 | homepage: string, | 18 | homepage: string |
19 | author: string, | 19 | author: string |
20 | bugs: string, | 20 | bugs: string |
21 | library: string, | 21 | library: string |
22 | 22 | ||
23 | staticDirs: { [ name: string ]: string } | 23 | staticDirs: { [ name: string ]: string } |
24 | css: string[] | 24 | css: string[] |
diff --git a/shared/models/plugins/server-hook.model.ts b/shared/models/plugins/server-hook.model.ts index 80ecd9e24..20f89b86d 100644 --- a/shared/models/plugins/server-hook.model.ts +++ b/shared/models/plugins/server-hook.model.ts | |||
@@ -70,7 +70,7 @@ export const serverActionHookObject = { | |||
70 | // Fired when a user is updated by an admin/moderator | 70 | // Fired when a user is updated by an admin/moderator |
71 | 'action:api.user.updated': true, | 71 | 'action:api.user.updated': true, |
72 | 72 | ||
73 | // Fired when a user got a new oauth2 token | 73 | // Fired when a user got a new oauth2 token |
74 | 'action:api.user.oauth2-got-token': true | 74 | 'action:api.user.oauth2-got-token': true |
75 | } | 75 | } |
76 | 76 | ||
diff --git a/shared/models/redundancy/index.ts b/shared/models/redundancy/index.ts index 61bf0fca7..649cc489f 100644 --- a/shared/models/redundancy/index.ts +++ b/shared/models/redundancy/index.ts | |||
@@ -1 +1,3 @@ | |||
1 | export * from './videos-redundancy.model' | 1 | export * from './videos-redundancy-strategy.model' |
2 | export * from './video-redundancies-filters.model' | ||
3 | export * from './video-redundancy.model' | ||
diff --git a/shared/models/redundancy/video-redundancies-filters.model.ts b/shared/models/redundancy/video-redundancies-filters.model.ts new file mode 100644 index 000000000..05ba7dfd3 --- /dev/null +++ b/shared/models/redundancy/video-redundancies-filters.model.ts | |||
@@ -0,0 +1 @@ | |||
export type VideoRedundanciesTarget = 'my-videos' | 'remote-videos' | |||
diff --git a/shared/models/redundancy/video-redundancy.model.ts b/shared/models/redundancy/video-redundancy.model.ts new file mode 100644 index 000000000..fa6e05832 --- /dev/null +++ b/shared/models/redundancy/video-redundancy.model.ts | |||
@@ -0,0 +1,35 @@ | |||
1 | export interface VideoRedundancy { | ||
2 | id: number | ||
3 | name: string | ||
4 | url: string | ||
5 | uuid: string | ||
6 | |||
7 | redundancies: { | ||
8 | files: FileRedundancyInformation[] | ||
9 | |||
10 | streamingPlaylists: StreamingPlaylistRedundancyInformation[] | ||
11 | } | ||
12 | } | ||
13 | |||
14 | interface RedundancyInformation { | ||
15 | id: number | ||
16 | fileUrl: string | ||
17 | strategy: string | ||
18 | |||
19 | createdAt: Date | string | ||
20 | updatedAt: Date | string | ||
21 | |||
22 | expiresOn: Date | string | ||
23 | |||
24 | size: number | ||
25 | } | ||
26 | |||
27 | // eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
28 | export interface FileRedundancyInformation extends RedundancyInformation { | ||
29 | |||
30 | } | ||
31 | |||
32 | // eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
33 | export interface StreamingPlaylistRedundancyInformation extends RedundancyInformation { | ||
34 | |||
35 | } | ||
diff --git a/shared/models/redundancy/videos-redundancy.model.ts b/shared/models/redundancy/videos-redundancy-strategy.model.ts index a8c2743c1..15409abf0 100644 --- a/shared/models/redundancy/videos-redundancy.model.ts +++ b/shared/models/redundancy/videos-redundancy-strategy.model.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | export type VideoRedundancyStrategy = 'most-views' | 'trending' | 'recently-added' | 1 | export type VideoRedundancyStrategy = 'most-views' | 'trending' | 'recently-added' |
2 | export type VideoRedundancyStrategyWithManual = VideoRedundancyStrategy | 'manual' | ||
2 | 3 | ||
3 | export type MostViewsRedundancyStrategy = { | 4 | export type MostViewsRedundancyStrategy = { |
4 | strategy: 'most-views' | 5 | strategy: 'most-views' |
@@ -19,4 +20,4 @@ export type RecentlyAddedStrategy = { | |||
19 | minLifetime: number | 20 | minLifetime: number |
20 | } | 21 | } |
21 | 22 | ||
22 | export type VideosRedundancy = MostViewsRedundancyStrategy | TrendingRedundancyStrategy | RecentlyAddedStrategy | 23 | export type VideosRedundancyStrategy = MostViewsRedundancyStrategy | TrendingRedundancyStrategy | RecentlyAddedStrategy |
diff --git a/shared/models/server/custom-config.model.ts b/shared/models/server/custom-config.model.ts index 032b91a29..07e17bda2 100644 --- a/shared/models/server/custom-config.model.ts +++ b/shared/models/server/custom-config.model.ts | |||
@@ -97,7 +97,7 @@ export interface CustomConfig { | |||
97 | videos: { | 97 | videos: { |
98 | http: { | 98 | http: { |
99 | enabled: boolean | 99 | enabled: boolean |
100 | }, | 100 | } |
101 | torrent: { | 101 | torrent: { |
102 | enabled: boolean | 102 | enabled: boolean |
103 | } | 103 | } |
@@ -114,7 +114,7 @@ export interface CustomConfig { | |||
114 | 114 | ||
115 | followers: { | 115 | followers: { |
116 | instance: { | 116 | instance: { |
117 | enabled: boolean, | 117 | enabled: boolean |
118 | manualApproval: boolean | 118 | manualApproval: boolean |
119 | } | 119 | } |
120 | } | 120 | } |
diff --git a/shared/models/server/job.model.ts b/shared/models/server/job.model.ts index b82a633b2..cf29d20d4 100644 --- a/shared/models/server/job.model.ts +++ b/shared/models/server/job.model.ts | |||
@@ -1,22 +1,24 @@ | |||
1 | export type JobState = 'active' | 'completed' | 'failed' | 'waiting' | 'delayed' | 1 | export type JobState = 'active' | 'completed' | 'failed' | 'waiting' | 'delayed' |
2 | 2 | ||
3 | export type JobType = 'activitypub-http-unicast' | | 3 | export type JobType = |
4 | 'activitypub-http-broadcast' | | 4 | | 'activitypub-http-unicast' |
5 | 'activitypub-http-fetcher' | | 5 | | 'activitypub-http-broadcast' |
6 | 'activitypub-follow' | | 6 | | 'activitypub-http-fetcher' |
7 | 'video-file-import' | | 7 | | 'activitypub-follow' |
8 | 'video-transcoding' | | 8 | | 'video-file-import' |
9 | 'email' | | 9 | | 'video-transcoding' |
10 | 'video-import' | | 10 | | 'email' |
11 | 'videos-views' | | 11 | | 'video-import' |
12 | 'activitypub-refresher' | 12 | | 'videos-views' |
13 | | 'activitypub-refresher' | ||
14 | | 'video-redundancy' | ||
13 | 15 | ||
14 | export interface Job { | 16 | export interface Job { |
15 | id: number | 17 | id: number |
16 | state: JobState | 18 | state: JobState |
17 | type: JobType | 19 | type: JobType |
18 | data: any, | 20 | data: any |
19 | error: any, | 21 | error: any |
20 | createdAt: Date | string | 22 | createdAt: Date | string |
21 | finishedOn: Date | string | 23 | finishedOn: Date | string |
22 | processedOn: Date | string | 24 | processedOn: Date | string |
diff --git a/shared/models/server/server-config.model.ts b/shared/models/server/server-config.model.ts index f1bb2153c..76e0d6f2d 100644 --- a/shared/models/server/server-config.model.ts +++ b/shared/models/server/server-config.model.ts | |||
@@ -46,7 +46,7 @@ export interface ServerConfig { | |||
46 | } | 46 | } |
47 | 47 | ||
48 | signup: { | 48 | signup: { |
49 | allowed: boolean, | 49 | allowed: boolean |
50 | allowedForCurrentIP: boolean | 50 | allowedForCurrentIP: boolean |
51 | requiresEmailVerification: boolean | 51 | requiresEmailVerification: boolean |
52 | } | 52 | } |
@@ -97,7 +97,7 @@ export interface ServerConfig { | |||
97 | max: number | 97 | max: number |
98 | } | 98 | } |
99 | extensions: string[] | 99 | extensions: string[] |
100 | }, | 100 | } |
101 | file: { | 101 | file: { |
102 | extensions: string[] | 102 | extensions: string[] |
103 | } | 103 | } |
@@ -107,7 +107,7 @@ export interface ServerConfig { | |||
107 | file: { | 107 | file: { |
108 | size: { | 108 | size: { |
109 | max: number | 109 | max: number |
110 | }, | 110 | } |
111 | extensions: string[] | 111 | extensions: string[] |
112 | } | 112 | } |
113 | } | 113 | } |
diff --git a/shared/models/server/server-stats.model.ts b/shared/models/server/server-stats.model.ts index 74f3de5d3..11778e6ed 100644 --- a/shared/models/server/server-stats.model.ts +++ b/shared/models/server/server-stats.model.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { VideoRedundancyStrategy } from '../redundancy' | 1 | import { VideoRedundancyStrategyWithManual } from '../redundancy' |
2 | 2 | ||
3 | export interface ServerStats { | 3 | export interface ServerStats { |
4 | totalUsers: number | 4 | totalUsers: number |
@@ -13,11 +13,13 @@ export interface ServerStats { | |||
13 | totalInstanceFollowers: number | 13 | totalInstanceFollowers: number |
14 | totalInstanceFollowing: number | 14 | totalInstanceFollowing: number |
15 | 15 | ||
16 | videosRedundancy: { | 16 | videosRedundancy: VideosRedundancyStats[] |
17 | strategy: VideoRedundancyStrategy | 17 | } |
18 | totalSize: number | 18 | |
19 | totalUsed: number | 19 | export interface VideosRedundancyStats { |
20 | totalVideoFiles: number | 20 | strategy: VideoRedundancyStrategyWithManual |
21 | totalVideos: number | 21 | totalSize: number |
22 | }[] | 22 | totalUsed: number |
23 | totalVideoFiles: number | ||
24 | totalVideos: number | ||
23 | } | 25 | } |
diff --git a/shared/models/users/user-right.enum.ts b/shared/models/users/user-right.enum.ts index 4a28a229d..2f88a65de 100644 --- a/shared/models/users/user-right.enum.ts +++ b/shared/models/users/user-right.enum.ts | |||
@@ -33,5 +33,7 @@ export enum UserRight { | |||
33 | SEE_ALL_VIDEOS, | 33 | SEE_ALL_VIDEOS, |
34 | CHANGE_VIDEO_OWNERSHIP, | 34 | CHANGE_VIDEO_OWNERSHIP, |
35 | 35 | ||
36 | MANAGE_PLUGINS | 36 | MANAGE_PLUGINS, |
37 | |||
38 | MANAGE_VIDEOS_REDUNDANCIES | ||
37 | } | 39 | } |
diff --git a/shared/models/users/user-role.ts b/shared/models/users/user-role.ts index 0b6554e51..ae3a0d983 100644 --- a/shared/models/users/user-role.ts +++ b/shared/models/users/user-role.ts | |||
@@ -7,15 +7,13 @@ export enum UserRole { | |||
7 | USER = 2 | 7 | USER = 2 |
8 | } | 8 | } |
9 | 9 | ||
10 | // TODO: use UserRole for key once https://github.com/Microsoft/TypeScript/issues/13042 is fixed | 10 | export const USER_ROLE_LABELS: { [ id in UserRole ]: string } = { |
11 | export const USER_ROLE_LABELS: { [ id: number ]: string } = { | ||
12 | [UserRole.USER]: 'User', | 11 | [UserRole.USER]: 'User', |
13 | [UserRole.MODERATOR]: 'Moderator', | 12 | [UserRole.MODERATOR]: 'Moderator', |
14 | [UserRole.ADMINISTRATOR]: 'Administrator' | 13 | [UserRole.ADMINISTRATOR]: 'Administrator' |
15 | } | 14 | } |
16 | 15 | ||
17 | // TODO: use UserRole for key once https://github.com/Microsoft/TypeScript/issues/13042 is fixed | 16 | const userRoleRights: { [ id in UserRole ]: UserRight[] } = { |
18 | const userRoleRights: { [ id: number ]: UserRight[] } = { | ||
19 | [UserRole.ADMINISTRATOR]: [ | 17 | [UserRole.ADMINISTRATOR]: [ |
20 | UserRight.ALL | 18 | UserRight.ALL |
21 | ], | 19 | ], |
diff --git a/shared/models/users/user.model.ts b/shared/models/users/user.model.ts index 168851196..efb451014 100644 --- a/shared/models/users/user.model.ts +++ b/shared/models/users/user.model.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { Account } from '../actors' | 1 | import { Account } from '../actors' |
2 | import { VideoChannel } from '../videos/channel/video-channel.model' | 2 | import { VideoChannel } from '../videos/channel/video-channel.model' |
3 | import { VideoPlaylist } from '../videos/playlist/video-playlist.model' | ||
4 | import { UserRole } from './user-role' | 3 | import { UserRole } from './user-role' |
5 | import { NSFWPolicyType } from '../videos/nsfw-policy.type' | 4 | import { NSFWPolicyType } from '../videos/nsfw-policy.type' |
6 | import { UserNotificationSetting } from './user-notification-setting.model' | 5 | import { UserNotificationSetting } from './user-notification-setting.model' |
diff --git a/shared/models/videos/video-transcoding-fps.model.ts b/shared/models/videos/video-transcoding-fps.model.ts index 82022d2f1..25fc1c2da 100644 --- a/shared/models/videos/video-transcoding-fps.model.ts +++ b/shared/models/videos/video-transcoding-fps.model.ts | |||
@@ -1,6 +1,8 @@ | |||
1 | export type VideoTranscodingFPS = { | 1 | export type VideoTranscodingFPS = { |
2 | MIN: number, | 2 | MIN: number |
3 | AVERAGE: number, | 3 | STANDARD: number[] |
4 | MAX: number, | 4 | HD_STANDARD: number[] |
5 | AVERAGE: number | ||
6 | MAX: number | ||
5 | KEEP_ORIGIN_FPS_RESOLUTION_MIN: number | 7 | KEEP_ORIGIN_FPS_RESOLUTION_MIN: number |
6 | } | 8 | } |
diff --git a/shared/models/videos/video.model.ts b/shared/models/videos/video.model.ts index 7576439fe..a69152759 100644 --- a/shared/models/videos/video.model.ts +++ b/shared/models/videos/video.model.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { AccountSummary, VideoChannelSummary, VideoResolution, VideoState } from '../../index' | 1 | import { AccountSummary, VideoChannelSummary, VideoState } from '../../index' |
2 | import { Account } from '../actors' | 2 | import { Account } from '../actors' |
3 | import { VideoChannel } from './channel/video-channel.model' | 3 | import { VideoChannel } from './channel/video-channel.model' |
4 | import { VideoPrivacy } from './video-privacy.enum' | 4 | import { VideoPrivacy } from './video-privacy.enum' |
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml index 43718e2a1..907187e4c 100644 --- a/support/doc/api/openapi.yaml +++ b/support/doc/api/openapi.yaml | |||
@@ -977,6 +977,12 @@ paths: | |||
977 | application/json: | 977 | application/json: |
978 | schema: | 978 | schema: |
979 | $ref: '#/components/schemas/VideoUploadResponse' | 979 | $ref: '#/components/schemas/VideoUploadResponse' |
980 | '403': | ||
981 | description: 'The user video quota is exceeded with this video.' | ||
982 | '408': | ||
983 | description: 'Upload has timed out' | ||
984 | '422': | ||
985 | description: 'Invalid input file.' | ||
980 | requestBody: | 986 | requestBody: |
981 | content: | 987 | content: |
982 | multipart/form-data: | 988 | multipart/form-data: |
diff --git a/support/doc/production.md b/support/doc/production.md index 8f061f868..6febaba5d 100644 --- a/support/doc/production.md +++ b/support/doc/production.md | |||
@@ -39,7 +39,7 @@ Create the production database and a peertube user inside PostgreSQL: | |||
39 | 39 | ||
40 | ``` | 40 | ``` |
41 | $ sudo -u postgres createuser -P peertube | 41 | $ sudo -u postgres createuser -P peertube |
42 | $ sudo -u postgres createdb -O peertube peertube_prod | 42 | $ sudo -u postgres createdb -O peertube -E UTF8 -T template0 peertube_prod |
43 | ``` | 43 | ``` |
44 | 44 | ||
45 | Then enable extensions PeerTube needs: | 45 | Then enable extensions PeerTube needs: |
diff --git a/support/doc/tools.md b/support/doc/tools.md index d5427b5b7..1f1e52c36 100644 --- a/support/doc/tools.md +++ b/support/doc/tools.md | |||
@@ -12,6 +12,7 @@ | |||
12 | - [peertube-upload.js](#peertube-uploadjs) | 12 | - [peertube-upload.js](#peertube-uploadjs) |
13 | - [peertube-watch.js](#peertube-watchjs) | 13 | - [peertube-watch.js](#peertube-watchjs) |
14 | - [peertube-plugins.js](#peertube-pluginsjs) | 14 | - [peertube-plugins.js](#peertube-pluginsjs) |
15 | - [peertube-redundancy.js](#peertube-redundancyjs) | ||
15 | - [Server tools](#server-tools) | 16 | - [Server tools](#server-tools) |
16 | - [parse-log](#parse-log) | 17 | - [parse-log](#parse-log) |
17 | - [create-transcoding-job.js](#create-transcoding-jobjs) | 18 | - [create-transcoding-job.js](#create-transcoding-jobjs) |
@@ -77,7 +78,8 @@ You can access it as `peertube` via an alias in your `.bashrc` like `alias peert | |||
77 | import-videos|import import a video from a streaming platform | 78 | import-videos|import import a video from a streaming platform |
78 | watch|w watch a video in the terminal ✩°。⋆ | 79 | watch|w watch a video in the terminal ✩°。⋆ |
79 | repl initiate a REPL to access internals | 80 | repl initiate a REPL to access internals |
80 | plugins|p [action] manag instance plugins | 81 | plugins|p [action] manage instance plugins |
82 | redundancy|r [action] manage video redundancies | ||
81 | help [cmd] display help for [cmd] | 83 | help [cmd] display help for [cmd] |
82 | ``` | 84 | ``` |
83 | 85 | ||
@@ -200,6 +202,34 @@ $ node dist/server/tools/peertube-plugins.js install --path /my/plugin/path | |||
200 | $ node dist/server/tools/peertube-plugins.js install --npm-name peertube-theme-example | 202 | $ node dist/server/tools/peertube-plugins.js install --npm-name peertube-theme-example |
201 | ``` | 203 | ``` |
202 | 204 | ||
205 | #### peertube-redundancy.js | ||
206 | |||
207 | Manage (list/add/remove) video redundancies: | ||
208 | |||
209 | To list your videos that are duplicated by remote instances: | ||
210 | |||
211 | ``` | ||
212 | $ node dist/server/tools/peertube.js redundancy list-remote-redundancies | ||
213 | ``` | ||
214 | |||
215 | To list remote videos that your instance duplicated: | ||
216 | |||
217 | ``` | ||
218 | $ node dist/server/tools/peertube.js redundancy list-my-redundancies | ||
219 | ``` | ||
220 | |||
221 | To duplicate a specific video in your redundancy system: | ||
222 | |||
223 | ``` | ||
224 | $ node dist/server/tools/peertube.js redundancy add --video 823 | ||
225 | ``` | ||
226 | |||
227 | To remove a video redundancy: | ||
228 | |||
229 | ``` | ||
230 | $ node dist/server/tools/peertube.js redundancy remove --video 823 | ||
231 | ``` | ||
232 | |||
203 | ## Server tools | 233 | ## Server tools |
204 | 234 | ||
205 | These scripts should be run on the server, in `peertube-latest` directory. | 235 | These scripts should be run on the server, in `peertube-latest` directory. |
diff --git a/tslint.json b/tslint.json deleted file mode 100644 index cfe2ac712..000000000 --- a/tslint.json +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | { | ||
2 | "extends": "tslint-config-standard", | ||
3 | "rules": { | ||
4 | "await-promise": [true, "Bluebird"], | ||
5 | "no-inferrable-types": true, | ||
6 | "eofline": true, | ||
7 | "indent": [true, "spaces"], | ||
8 | "ter-indent": [ | ||
9 | true, | ||
10 | 2, | ||
11 | { | ||
12 | "SwitchCase": 1 | ||
13 | } | ||
14 | ], | ||
15 | "max-line-length": [true, 140], | ||
16 | "no-unused-variable": false, // Memory issues | ||
17 | "no-floating-promises": false | ||
18 | } | ||
19 | } | ||
@@ -3,49 +3,21 @@ | |||
3 | 3 | ||
4 | 4 | ||
5 | "@babel/code-frame@^7.0.0": | 5 | "@babel/code-frame@^7.0.0": |
6 | version "7.5.5" | 6 | version "7.8.3" |
7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" | 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" |
8 | integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== | 8 | integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== |
9 | dependencies: | 9 | dependencies: |
10 | "@babel/highlight" "^7.0.0" | 10 | "@babel/highlight" "^7.8.3" |
11 | 11 | ||
12 | "@babel/highlight@^7.0.0": | 12 | "@babel/highlight@^7.8.3": |
13 | version "7.5.0" | 13 | version "7.8.3" |
14 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" | 14 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" |
15 | integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== | 15 | integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== |
16 | dependencies: | 16 | dependencies: |
17 | chalk "^2.0.0" | 17 | chalk "^2.0.0" |
18 | esutils "^2.0.2" | 18 | esutils "^2.0.2" |
19 | js-tokens "^4.0.0" | 19 | js-tokens "^4.0.0" |
20 | 20 | ||
21 | "@nodelib/fs.scandir@2.1.3": | ||
22 | version "2.1.3" | ||
23 | resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" | ||
24 | integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== | ||
25 | dependencies: | ||
26 | "@nodelib/fs.stat" "2.0.3" | ||
27 | run-parallel "^1.1.9" | ||
28 | |||
29 | "@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": | ||
30 | version "2.0.3" | ||
31 | resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" | ||
32 | integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== | ||
33 | |||
34 | "@nodelib/fs.walk@^1.2.3": | ||
35 | version "1.2.4" | ||
36 | resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" | ||
37 | integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== | ||
38 | dependencies: | ||
39 | "@nodelib/fs.scandir" "2.1.3" | ||
40 | fastq "^1.6.0" | ||
41 | |||
42 | "@samverschueren/stream-to-observable@^0.3.0": | ||
43 | version "0.3.0" | ||
44 | resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f" | ||
45 | integrity sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg== | ||
46 | dependencies: | ||
47 | any-observable "^0.3.0" | ||
48 | |||
49 | "@types/apicache@^1.2.0": | 21 | "@types/apicache@^1.2.0": |
50 | version "1.2.2" | 22 | version "1.2.2" |
51 | resolved "https://registry.yarnpkg.com/@types/apicache/-/apicache-1.2.2.tgz#b820659b1d95e66ec0e71dcd0317e9d30f0c154b" | 23 | resolved "https://registry.yarnpkg.com/@types/apicache/-/apicache-1.2.2.tgz#b820659b1d95e66ec0e71dcd0317e9d30f0c154b" |
@@ -59,9 +31,9 @@ | |||
59 | integrity sha512-TU1X8jmAU2BjwKryBFV/GDezz7Ge0xu9ZuYC7dy6wKj4hnL0JcxeseCOr/G2JkGylff6hdUBrR+Ee5ApAQeU5g== | 31 | integrity sha512-TU1X8jmAU2BjwKryBFV/GDezz7Ge0xu9ZuYC7dy6wKj4hnL0JcxeseCOr/G2JkGylff6hdUBrR+Ee5ApAQeU5g== |
60 | 32 | ||
61 | "@types/async@^3.0.0": | 33 | "@types/async@^3.0.0": |
62 | version "3.0.3" | 34 | version "3.0.7" |
63 | resolved "https://registry.yarnpkg.com/@types/async/-/async-3.0.3.tgz#ea3694128c757580e4f9328cd941b81d9c3e9bf6" | 35 | resolved "https://registry.yarnpkg.com/@types/async/-/async-3.0.7.tgz#ef2733a3d027a81cd86524d0650db55f5d8cdff6" |
64 | integrity sha512-FrIcC67Zpko1jO8K4d30C41/KVhAABbMbaSxccvXacxPcKbDBav+8WoFzv72BA2zJvyX4T9PFz0we1hcNymgGA== | 36 | integrity sha512-Oqf/gYXRnUkYL0xYB5gCLr5Ft/3yckVWie8W8TPngOeT56n+NrnHRtu9xbTvFXzxA7vfaK+gPdCjFiFCyBfEPg== |
65 | 37 | ||
66 | "@types/bcrypt@^3.0.0": | 38 | "@types/bcrypt@^3.0.0": |
67 | version "3.0.0" | 39 | version "3.0.0" |
@@ -75,15 +47,10 @@ | |||
75 | dependencies: | 47 | dependencies: |
76 | "@types/node" "*" | 48 | "@types/node" "*" |
77 | 49 | ||
78 | "@types/bluebird@*", "@types/bluebird@3.5.27": | 50 | "@types/bluebird@3.5.29": |
79 | version "3.5.27" | 51 | version "3.5.29" |
80 | resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.27.tgz#61eb4d75dc6bfbce51cf49ee9bbebe941b2cb5d0" | 52 | resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.29.tgz#7cd933c902c4fc83046517a1bef973886d00bdb6" |
81 | integrity sha512-6BmYWSBea18+tSjjSC3QIyV93ZKAeNWGM7R6aYt1ryTZXrlHF+QLV0G2yV0viEGVyRkyQsWfMoJ0k/YghBX5sQ== | 53 | integrity sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw== |
82 | |||
83 | "@types/bluebird@3.5.21": | ||
84 | version "3.5.21" | ||
85 | resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.21.tgz#567615589cc913e84a28ecf9edb031732bdf2634" | ||
86 | integrity sha512-6UNEwyw+6SGMC/WMI0ld0PS4st7Qq51qgguFrFizOSpGvZiqe9iswztFSdZvwJBEhLOy2JaxNE6VC7yMAlbfyQ== | ||
87 | 54 | ||
88 | "@types/body-parser@*", "@types/body-parser@^1.16.3": | 55 | "@types/body-parser@*", "@types/body-parser@^1.16.3": |
89 | version "1.17.1" | 56 | version "1.17.1" |
@@ -93,12 +60,11 @@ | |||
93 | "@types/connect" "*" | 60 | "@types/connect" "*" |
94 | "@types/node" "*" | 61 | "@types/node" "*" |
95 | 62 | ||
96 | "@types/bull@3.4.0": | 63 | "@types/bull@3.12.0": |
97 | version "3.4.0" | 64 | version "3.12.0" |
98 | resolved "https://registry.yarnpkg.com/@types/bull/-/bull-3.4.0.tgz#18ffefefa4dd1cfbdbdc8ca7df56c934459f6b9d" | 65 | resolved "https://registry.yarnpkg.com/@types/bull/-/bull-3.12.0.tgz#683d7a08db64823076c4b5ac00eea73e5b6947fa" |
99 | integrity sha512-NVD2X+cUu1qNv6blsOfCr2fVsD3+O13U19dFuy9Du7PWfn1/gjFZEDk220uBuRSH5JyaP4nV6S8BLjsT5/bXUg== | 66 | integrity sha512-oKj9X8bxBF7OyAsCPGg2hu9msQPM/WwIRJfUHd0xzmKDMYOBepzbWdIuQDoX1xyvDskdjbW2Io7chbxqARae7A== |
100 | dependencies: | 67 | dependencies: |
101 | "@types/bluebird" "*" | ||
102 | "@types/ioredis" "*" | 68 | "@types/ioredis" "*" |
103 | 69 | ||
104 | "@types/bytes@^3.0.0": | 70 | "@types/bytes@^3.0.0": |
@@ -126,9 +92,9 @@ | |||
126 | "@types/chai" "*" | 92 | "@types/chai" "*" |
127 | 93 | ||
128 | "@types/chai@*", "@types/chai@^4.0.4": | 94 | "@types/chai@*", "@types/chai@^4.0.4": |
129 | version "4.2.7" | 95 | version "4.2.8" |
130 | resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.7.tgz#1c8c25cbf6e59ffa7d6b9652c78e547d9a41692d" | 96 | resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.8.tgz#c8d645506db0d15f4aafd4dfa873f443ad87ea59" |
131 | integrity sha512-luq8meHGYwvky0O7u0eQZdA7B4Wd9owUCqvbw2m3XCrCU8mplYOujMBbvyS547AxJkC+pGnd0Cm15eNxEUNU8g== | 97 | integrity sha512-U1bQiWbln41Yo6EeHMr+34aUhvrMVyrhn9lYfPSpLTCrZlGxU4Rtn1bocX+0p2Fc/Jkd2FanCEXdw0WNfHHM0w== |
132 | 98 | ||
133 | "@types/color-name@^1.1.1": | 99 | "@types/color-name@^1.1.1": |
134 | version "1.1.1" | 100 | version "1.1.1" |
@@ -152,10 +118,10 @@ | |||
152 | resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80" | 118 | resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80" |
153 | integrity sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw== | 119 | integrity sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw== |
154 | 120 | ||
155 | "@types/events@*": | 121 | "@types/eslint-visitor-keys@^1.0.0": |
156 | version "3.0.0" | 122 | version "1.0.0" |
157 | resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" | 123 | resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" |
158 | integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== | 124 | integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== |
159 | 125 | ||
160 | "@types/express-rate-limit@^3.3.0": | 126 | "@types/express-rate-limit@^3.3.0": |
161 | version "3.3.3" | 127 | version "3.3.3" |
@@ -165,9 +131,9 @@ | |||
165 | "@types/express" "*" | 131 | "@types/express" "*" |
166 | 132 | ||
167 | "@types/express-serve-static-core@*": | 133 | "@types/express-serve-static-core@*": |
168 | version "4.17.1" | 134 | version "4.17.2" |
169 | resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.1.tgz#82be64a77211b205641e0209096fd3afb62481d3" | 135 | resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.2.tgz#f6f41fa35d42e79dbf6610eccbb2637e6008a0cf" |
170 | integrity sha512-9e7jj549ZI+RxY21Cl0t8uBnWyb22HzILupyHZjYEVK//5TT/1bZodU+yUbLnPdoYViBBnNWbxp4zYjGV0zUGw== | 136 | integrity sha512-El9yMpctM6tORDAiBwZVLMcxoTMcqqRO9dVyYcn7ycLWbvR8klrDn8CAOwRfZujZtWD7yS/mshTdz43jMOejbg== |
171 | dependencies: | 137 | dependencies: |
172 | "@types/node" "*" | 138 | "@types/node" "*" |
173 | "@types/range-parser" "*" | 139 | "@types/range-parser" "*" |
@@ -195,22 +161,18 @@ | |||
195 | dependencies: | 161 | dependencies: |
196 | "@types/node" "*" | 162 | "@types/node" "*" |
197 | 163 | ||
198 | "@types/glob@^7.1.1": | ||
199 | version "7.1.1" | ||
200 | resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" | ||
201 | integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== | ||
202 | dependencies: | ||
203 | "@types/events" "*" | ||
204 | "@types/minimatch" "*" | ||
205 | "@types/node" "*" | ||
206 | |||
207 | "@types/ioredis@*": | 164 | "@types/ioredis@*": |
208 | version "4.14.3" | 165 | version "4.14.6" |
209 | resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.14.3.tgz#6a6089296d6fb90bbaee96d36b19d480efff026a" | 166 | resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.14.6.tgz#446403ab0360bf12d010ba8bbd0670b292f12143" |
210 | integrity sha512-WM9xJkP+ckvr8DFy2bFEPWEp7454L/4cBT11qhqPqyzdyZ+8DxUfkf/yo+rQGQJbld0agY2PI5Jb3xxC7KZs6g== | 167 | integrity sha512-VUbEZaeCfdiqfd3UDtmPpwewCBdbnjpMZtarKuZV7XwkhqgBZN208WQpsD3hT0BJqEx3GPApFnIVnIOq/eBpbA== |
211 | dependencies: | 168 | dependencies: |
212 | "@types/node" "*" | 169 | "@types/node" "*" |
213 | 170 | ||
171 | "@types/json-schema@^7.0.3": | ||
172 | version "7.0.4" | ||
173 | resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" | ||
174 | integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== | ||
175 | |||
214 | "@types/json5@^0.0.29": | 176 | "@types/json5@^0.0.29": |
215 | version "0.0.29" | 177 | version "0.0.29" |
216 | resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" | 178 | resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" |
@@ -257,11 +219,6 @@ | |||
257 | resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" | 219 | resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" |
258 | integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== | 220 | integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== |
259 | 221 | ||
260 | "@types/minimatch@*": | ||
261 | version "3.0.3" | ||
262 | resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" | ||
263 | integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== | ||
264 | |||
265 | "@types/mkdirp@^0.5.1": | 222 | "@types/mkdirp@^0.5.1": |
266 | version "0.5.2" | 223 | version "0.5.2" |
267 | resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.2.tgz#503aacfe5cc2703d5484326b1b27efa67a339c1f" | 224 | resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.2.tgz#503aacfe5cc2703d5484326b1b27efa67a339c1f" |
@@ -269,10 +226,10 @@ | |||
269 | dependencies: | 226 | dependencies: |
270 | "@types/node" "*" | 227 | "@types/node" "*" |
271 | 228 | ||
272 | "@types/mocha@^5.0.0": | 229 | "@types/mocha@^7.0.1": |
273 | version "5.2.7" | 230 | version "7.0.1" |
274 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" | 231 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.1.tgz#5d7ec2a789a1f77c59b7ad071b9d50bf1abbfc9e" |
275 | integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== | 232 | integrity sha512-L/Nw/2e5KUaprNJoRA33oly+M8X8n0K+FwLTbYqwTcR14wdPWeRkigBLfSFpN/Asf9ENZTMZwLxjtjeYucAA4Q== |
276 | 233 | ||
277 | "@types/morgan@^1.7.32": | 234 | "@types/morgan@^1.7.32": |
278 | version "1.7.37" | 235 | version "1.7.37" |
@@ -282,26 +239,26 @@ | |||
282 | "@types/express" "*" | 239 | "@types/express" "*" |
283 | 240 | ||
284 | "@types/multer@^1.3.3": | 241 | "@types/multer@^1.3.3": |
285 | version "1.3.10" | 242 | version "1.4.0" |
286 | resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.3.10.tgz#d7afbd916f688fceb4460320e62a8ad1ab3e3cad" | 243 | resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.4.0.tgz#a4a83bee02696f61f63b65a87f9ebe8bdf12b767" |
287 | integrity sha512-3hECfz+W0ix/LvPanp87mjO3kOyDnJYTpY9y7gdBxXnYXqEcj21pD0lW7KEUFFr8CHrDF5Mhh7o241KLEXDRoQ== | 244 | integrity sha512-mF3lGy1HTixLELNGufKTvLWGUZKd0Amz/nZYj79nzCXWye2wTlgIo4CZ+mze7xMkezcWmQviV9uXYRMpZ0qk1w== |
288 | dependencies: | 245 | dependencies: |
289 | "@types/express" "*" | 246 | "@types/express" "*" |
290 | 247 | ||
291 | "@types/node@*": | 248 | "@types/node@*": |
292 | version "13.1.4" | 249 | version "13.5.3" |
293 | resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.4.tgz#4cfd90175a200ee9b02bd6b1cd19bc349741607e" | 250 | resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.3.tgz#37f1f539b7535b9fb4ef77d59db1847a837b7f17" |
294 | integrity sha512-Lue/mlp2egZJoHXZr4LndxDAd7i/7SQYhV0EjWfb/a4/OZ6tuVwMCVPiwkU5nsEipxEf7hmkSU7Em5VQ8P5NGA== | 251 | integrity sha512-ZPnWX9PW992w6DUsz3JIXHaSb5v7qmKCVzC3km6SxcDGxk7zmLfYaCJTbktIa5NeywJkkZDhGldKqDIvC5DRrA== |
295 | 252 | ||
296 | "@types/node@^10.0.8": | 253 | "@types/node@^10.0.8": |
297 | version "10.17.13" | 254 | version "10.17.14" |
298 | resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.13.tgz#ccebcdb990bd6139cd16e84c39dc2fb1023ca90c" | 255 | resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.14.tgz#b6c60ebf2fb5e4229fdd751ff9ddfae0f5f31541" |
299 | integrity sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg== | 256 | integrity sha512-G0UmX5uKEmW+ZAhmZ6PLTQ5eu/VPaT+d/tdLd5IFsKRPcbe6lPxocBtcYBFSaLaCW8O60AX90e91Nsp8lVHCNw== |
300 | 257 | ||
301 | "@types/node@^12.12.3": | 258 | "@types/node@^12.12.3": |
302 | version "12.12.24" | 259 | version "12.12.26" |
303 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.24.tgz#d4606afd8cf6c609036b854360367d1b2c78931f" | 260 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.26.tgz#213e153babac0ed169d44a6d919501e68f59dea9" |
304 | integrity sha512-1Ciqv9pqwVtW6FsIUKSZNB82E5Cu1I2bBTj1xuIHXLe/1zYLl3956Nbhg2MzSYHVfl9/rmanjbQIb7LibfCnug== | 261 | integrity sha512-UmUm94/QZvU5xLcUlNR8hA7Ac+fGpO1EG/a8bcWVz0P0LqtxFmun9Y2bbtuckwGboWJIT70DoWq1r3hb56n3DA== |
305 | 262 | ||
306 | "@types/nodemailer@^6.2.0": | 263 | "@types/nodemailer@^6.2.0": |
307 | version "6.4.0" | 264 | version "6.4.0" |
@@ -363,9 +320,9 @@ | |||
363 | form-data "^2.5.0" | 320 | form-data "^2.5.0" |
364 | 321 | ||
365 | "@types/sax@^1.2.0": | 322 | "@types/sax@^1.2.0": |
366 | version "1.2.0" | 323 | version "1.2.1" |
367 | resolved "https://registry.yarnpkg.com/@types/sax/-/sax-1.2.0.tgz#6025e0b7fc7cd5f3d83808a6809730bac798565d" | 324 | resolved "https://registry.yarnpkg.com/@types/sax/-/sax-1.2.1.tgz#e0248be936ece791a82db1a57f3fb5f7c87e8172" |
368 | integrity sha512-D8ef/GGUjiHuUOiXV6tkJw6Zq2Sm8vcBScJSvj+monDI5YncJ6M3oNIXR7EtmWPVqJw0jsZF2ARN/X5gvGmQSA== | 325 | integrity sha512-dqYdvN7Sbw8QT/0Ci5rhjE4/iCMJEM0Y9rHpCu+gGXD9Lwbz28t6HI2yegsB6BoV1sShRMU6lAmAcgRjmFy7LA== |
369 | dependencies: | 326 | dependencies: |
370 | "@types/node" "*" | 327 | "@types/node" "*" |
371 | 328 | ||
@@ -377,10 +334,10 @@ | |||
377 | "@types/express-serve-static-core" "*" | 334 | "@types/express-serve-static-core" "*" |
378 | "@types/mime" "*" | 335 | "@types/mime" "*" |
379 | 336 | ||
380 | "@types/sharp@^0.23.0": | 337 | "@types/sharp@^0.24.0": |
381 | version "0.23.1" | 338 | version "0.24.0" |
382 | resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.23.1.tgz#1e02560371d6603adc121389512f0745028aa507" | 339 | resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.24.0.tgz#28abfeac45b4dcb472305503105322e97a6c2672" |
383 | integrity sha512-iBRM9RjRF9pkIkukk6imlxfaKMRuiRND8L0yYKl5PJu5uLvxuNzp5f0x8aoTG5VX85M8O//BwbttzFVZL1j/FQ== | 340 | integrity sha512-+0WeyJajTSoIacBzonsq856whNJC+cN9FNEs0yZ6hFq/V1CZmlqM8vBRy7TKZunH+gIO7SwDCzgXYWRRbzqfDA== |
384 | dependencies: | 341 | dependencies: |
385 | "@types/node" "*" | 342 | "@types/node" "*" |
386 | 343 | ||
@@ -438,13 +395,56 @@ | |||
438 | "@types/parse-torrent" "*" | 395 | "@types/parse-torrent" "*" |
439 | "@types/simple-peer" "*" | 396 | "@types/simple-peer" "*" |
440 | 397 | ||
441 | "@types/ws@^6.0.0": | 398 | "@types/ws@^7.2.1": |
442 | version "6.0.4" | 399 | version "7.2.1" |
443 | resolved "https://registry.yarnpkg.com/@types/ws/-/ws-6.0.4.tgz#7797707c8acce8f76d8c34b370d4645b70421ff1" | 400 | resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.2.1.tgz#b800f2b8aee694e2b581113643e20d79dd3b8556" |
444 | integrity sha512-PpPrX7SZW9re6+Ha8ojZG4Se8AZXgf0GK6zmfqEuCsY49LFDNXO3SByp44X3dFEqtB73lkCDAdUazhAjVPiNwg== | 401 | integrity sha512-UEmRNbXFGvfs/sLncf01GuVv6U1mZP3Df0iXWx4kUlikJxbFyFADp95mDn1XDTE2mXpzzoHcKlfFcbytLq4vaA== |
445 | dependencies: | 402 | dependencies: |
446 | "@types/node" "*" | 403 | "@types/node" "*" |
447 | 404 | ||
405 | "@typescript-eslint/eslint-plugin@^2.18.0": | ||
406 | version "2.18.0" | ||
407 | resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.18.0.tgz#f8cf272dfb057ecf1ea000fea1e0b3f06a32f9cb" | ||
408 | integrity sha512-kuO8WQjV+RCZvAXVRJfXWiJ8iYEtfHlKgcqqqXg9uUkIolEHuUaMmm8/lcO4xwCOtaw6mY0gStn2Lg4/eUXXYQ== | ||
409 | dependencies: | ||
410 | "@typescript-eslint/experimental-utils" "2.18.0" | ||
411 | eslint-utils "^1.4.3" | ||
412 | functional-red-black-tree "^1.0.1" | ||
413 | regexpp "^3.0.0" | ||
414 | tsutils "^3.17.1" | ||
415 | |||
416 | "@typescript-eslint/experimental-utils@2.18.0": | ||
417 | version "2.18.0" | ||
418 | resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.18.0.tgz#e4eab839082030282496c1439bbf9fdf2a4f3da8" | ||
419 | integrity sha512-J6MopKPHuJYmQUkANLip7g9I82ZLe1naCbxZZW3O2sIxTiq/9YYoOELEKY7oPg0hJ0V/AQ225h2z0Yp+RRMXhw== | ||
420 | dependencies: | ||
421 | "@types/json-schema" "^7.0.3" | ||
422 | "@typescript-eslint/typescript-estree" "2.18.0" | ||
423 | eslint-scope "^5.0.0" | ||
424 | |||
425 | "@typescript-eslint/parser@^2.10.0": | ||
426 | version "2.18.0" | ||
427 | resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.18.0.tgz#d5f7fc1839abd4a985394e40e9d2454bd56aeb1f" | ||
428 | integrity sha512-SJJPxFMEYEWkM6pGfcnjLU+NJIPo+Ko1QrCBL+i0+zV30ggLD90huEmMMhKLHBpESWy9lVEeWlQibweNQzyc+A== | ||
429 | dependencies: | ||
430 | "@types/eslint-visitor-keys" "^1.0.0" | ||
431 | "@typescript-eslint/experimental-utils" "2.18.0" | ||
432 | "@typescript-eslint/typescript-estree" "2.18.0" | ||
433 | eslint-visitor-keys "^1.1.0" | ||
434 | |||
435 | "@typescript-eslint/typescript-estree@2.18.0": | ||
436 | version "2.18.0" | ||
437 | resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.18.0.tgz#cfbd16ed1b111166617d718619c19b62764c8460" | ||
438 | integrity sha512-gVHylf7FDb8VSi2ypFuEL3hOtoC4HkZZ5dOjXvVjoyKdRrvXAOPSzpNRnKMfaUUEiSLP8UF9j9X9EDLxC0lfZg== | ||
439 | dependencies: | ||
440 | debug "^4.1.1" | ||
441 | eslint-visitor-keys "^1.1.0" | ||
442 | glob "^7.1.6" | ||
443 | is-glob "^4.0.1" | ||
444 | lodash "^4.17.15" | ||
445 | semver "^6.3.0" | ||
446 | tsutils "^3.17.1" | ||
447 | |||
448 | abbrev@1: | 448 | abbrev@1: |
449 | version "1.1.1" | 449 | version "1.1.1" |
450 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" | 450 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" |
@@ -458,6 +458,16 @@ accepts@~1.3.4, accepts@~1.3.7: | |||
458 | mime-types "~2.1.24" | 458 | mime-types "~2.1.24" |
459 | negotiator "0.6.2" | 459 | negotiator "0.6.2" |
460 | 460 | ||
461 | acorn-jsx@^5.1.0: | ||
462 | version "5.1.0" | ||
463 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384" | ||
464 | integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw== | ||
465 | |||
466 | acorn@^7.1.0: | ||
467 | version "7.1.0" | ||
468 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" | ||
469 | integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== | ||
470 | |||
461 | addr-to-ip-port@^1.0.1, addr-to-ip-port@^1.4.2: | 471 | addr-to-ip-port@^1.0.1, addr-to-ip-port@^1.4.2: |
462 | version "1.5.1" | 472 | version "1.5.1" |
463 | resolved "https://registry.yarnpkg.com/addr-to-ip-port/-/addr-to-ip-port-1.5.1.tgz#bfada13fd6aeeeac19f1e9f7d84b4bbab45e5208" | 473 | resolved "https://registry.yarnpkg.com/addr-to-ip-port/-/addr-to-ip-port-1.5.1.tgz#bfada13fd6aeeeac19f1e9f7d84b4bbab45e5208" |
@@ -473,20 +483,12 @@ after@0.8.2: | |||
473 | resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" | 483 | resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" |
474 | integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= | 484 | integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= |
475 | 485 | ||
476 | aggregate-error@^3.0.0: | 486 | ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5: |
477 | version "3.0.1" | 487 | version "6.11.0" |
478 | resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" | 488 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9" |
479 | integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA== | 489 | integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA== |
480 | dependencies: | 490 | dependencies: |
481 | clean-stack "^2.0.0" | 491 | fast-deep-equal "^3.1.1" |
482 | indent-string "^4.0.0" | ||
483 | |||
484 | ajv@^6.5.5: | ||
485 | version "6.10.2" | ||
486 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" | ||
487 | integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== | ||
488 | dependencies: | ||
489 | fast-deep-equal "^2.0.1" | ||
490 | fast-json-stable-stringify "^2.0.0" | 492 | fast-json-stable-stringify "^2.0.0" |
491 | json-schema-traverse "^0.4.1" | 493 | json-schema-traverse "^0.4.1" |
492 | uri-js "^4.2.2" | 494 | uri-js "^4.2.2" |
@@ -503,10 +505,12 @@ ansi-colors@3.2.3: | |||
503 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" | 505 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" |
504 | integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== | 506 | integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== |
505 | 507 | ||
506 | ansi-escapes@^3.0.0: | 508 | ansi-escapes@^4.2.1: |
507 | version "3.2.0" | 509 | version "4.3.0" |
508 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" | 510 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d" |
509 | integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== | 511 | integrity sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg== |
512 | dependencies: | ||
513 | type-fest "^0.8.1" | ||
510 | 514 | ||
511 | ansi-regex@^2.0.0: | 515 | ansi-regex@^2.0.0: |
512 | version "2.1.1" | 516 | version "2.1.1" |
@@ -528,11 +532,6 @@ ansi-regex@^5.0.0: | |||
528 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" | 532 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" |
529 | integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== | 533 | integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== |
530 | 534 | ||
531 | ansi-styles@^2.2.1: | ||
532 | version "2.2.1" | ||
533 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" | ||
534 | integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= | ||
535 | |||
536 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: | 535 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: |
537 | version "3.2.1" | 536 | version "3.2.1" |
538 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" | 537 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" |
@@ -548,11 +547,6 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: | |||
548 | "@types/color-name" "^1.1.1" | 547 | "@types/color-name" "^1.1.1" |
549 | color-convert "^2.0.1" | 548 | color-convert "^2.0.1" |
550 | 549 | ||
551 | any-observable@^0.3.0: | ||
552 | version "0.3.0" | ||
553 | resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" | ||
554 | integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== | ||
555 | |||
556 | any-promise@^1.3.0: | 550 | any-promise@^1.3.0: |
557 | version "1.3.0" | 551 | version "1.3.0" |
558 | resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" | 552 | resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" |
@@ -567,9 +561,9 @@ anymatch@~3.1.1: | |||
567 | picomatch "^2.0.4" | 561 | picomatch "^2.0.4" |
568 | 562 | ||
569 | apicache@^1.4.0: | 563 | apicache@^1.4.0: |
570 | version "1.5.2" | 564 | version "1.5.3" |
571 | resolved "https://registry.yarnpkg.com/apicache/-/apicache-1.5.2.tgz#2cb0697d9b1b612b505b1a44face66d48b1d1404" | 565 | resolved "https://registry.yarnpkg.com/apicache/-/apicache-1.5.3.tgz#8977b358bf7d579d55fe3d183c907ae5dbcfb357" |
572 | integrity sha512-jO8ie/Zqmr3MxLQSVNsHiQo5R1tbbP1TnpI6xOnRJv9wUOSP+YnZkULWmdo3fE7PHBSxIQzgIsEHGa6H5hKH9Q== | 566 | integrity sha512-n1h39Bt7tMiJMV0u0tFlhigig8Uo/wJmKoj6WE/OwvZ+WbFchn7jnXleotZOzZTUBtr0Tg9iJshHnJDAGQbAEQ== |
573 | 567 | ||
574 | append-field@^1.0.0: | 568 | append-field@^1.0.0: |
575 | version "1.0.0" | 569 | version "1.0.0" |
@@ -606,10 +600,22 @@ array-flatten@1.1.1: | |||
606 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" | 600 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" |
607 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= | 601 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= |
608 | 602 | ||
609 | array-union@^2.1.0: | 603 | array-includes@^3.0.3: |
610 | version "2.1.0" | 604 | version "3.1.1" |
611 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" | 605 | resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" |
612 | integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== | 606 | integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== |
607 | dependencies: | ||
608 | define-properties "^1.1.3" | ||
609 | es-abstract "^1.17.0" | ||
610 | is-string "^1.0.5" | ||
611 | |||
612 | array.prototype.flat@^1.2.1: | ||
613 | version "1.2.3" | ||
614 | resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" | ||
615 | integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== | ||
616 | dependencies: | ||
617 | define-properties "^1.1.3" | ||
618 | es-abstract "^1.17.0-next.1" | ||
613 | 619 | ||
614 | arraybuffer.slice@~0.0.7: | 620 | arraybuffer.slice@~0.0.7: |
615 | version "0.0.7" | 621 | version "0.0.7" |
@@ -638,6 +644,11 @@ assertion-error@^1.1.0: | |||
638 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" | 644 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" |
639 | integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== | 645 | integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== |
640 | 646 | ||
647 | astral-regex@^1.0.0: | ||
648 | version "1.0.0" | ||
649 | resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" | ||
650 | integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== | ||
651 | |||
641 | async-limiter@~1.0.0: | 652 | async-limiter@~1.0.0: |
642 | version "1.0.1" | 653 | version "1.0.1" |
643 | resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" | 654 | resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" |
@@ -651,9 +662,9 @@ async-lru@^1.1.1: | |||
651 | lru "^3.1.0" | 662 | lru "^3.1.0" |
652 | 663 | ||
653 | async@>=0.2.9, async@^3.0.1, async@^3.1.0: | 664 | async@>=0.2.9, async@^3.0.1, async@^3.1.0: |
654 | version "3.1.0" | 665 | version "3.1.1" |
655 | resolved "https://registry.yarnpkg.com/async/-/async-3.1.0.tgz#42b3b12ae1b74927b5217d8c0016baaf62463772" | 666 | resolved "https://registry.yarnpkg.com/async/-/async-3.1.1.tgz#dd3542db03de837979c9ebbca64ca01b06dc98df" |
656 | integrity sha512-4vx/aaY6j/j3Lw3fbCHNWP0pPaTCew3F6F3hYyl/tHs/ndmV1q7NW9T5yuJ2XAGwdQrP+6Wu20x06U4APo/iQQ== | 667 | integrity sha512-X5Dj8hK1pJNC2Wzo2Rcp9FBVdJMGRR/S7V+lH46s8GVFhtbo5O4Le5GECCF/8PISVdkUA6mMPvgz7qTTD1rf1g== |
657 | 668 | ||
658 | async@^2.6.1: | 669 | async@^2.6.1: |
659 | version "2.6.3" | 670 | version "2.6.3" |
@@ -683,9 +694,9 @@ aws-sign2@~0.7.0: | |||
683 | integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= | 694 | integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= |
684 | 695 | ||
685 | aws4@^1.8.0: | 696 | aws4@^1.8.0: |
686 | version "1.9.0" | 697 | version "1.9.1" |
687 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.0.tgz#24390e6ad61386b0a747265754d2a17219de862c" | 698 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" |
688 | integrity sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A== | 699 | integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== |
689 | 700 | ||
690 | backo2@1.0.2: | 701 | backo2@1.0.2: |
691 | version "1.0.2" | 702 | version "1.0.2" |
@@ -903,9 +914,9 @@ body-parser@1.19.0, body-parser@^1.12.4: | |||
903 | type-is "~1.6.17" | 914 | type-is "~1.6.17" |
904 | 915 | ||
905 | bowser@^2.7.0: | 916 | bowser@^2.7.0: |
906 | version "2.8.1" | 917 | version "2.9.0" |
907 | resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.8.1.tgz#35b74165e17b80ba8af6aa4736c2861b001fc09e" | 918 | resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.9.0.tgz#3bed854233b419b9a7422d9ee3e85504373821c9" |
908 | integrity sha512-FxxltGKqMHkVa3KtpA+kdnxH0caHPDewccyrK3vW1bsMw6Zco4vRPmMunowX0pXlDZqhxkKSpToADQI2Sk4OeQ== | 919 | integrity sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA== |
909 | 920 | ||
910 | boxen@^1.2.1: | 921 | boxen@^1.2.1: |
911 | version "1.3.0" | 922 | version "1.3.0" |
@@ -928,7 +939,7 @@ brace-expansion@^1.1.7: | |||
928 | balanced-match "^1.0.0" | 939 | balanced-match "^1.0.0" |
929 | concat-map "0.0.1" | 940 | concat-map "0.0.1" |
930 | 941 | ||
931 | braces@^3.0.1, braces@~3.0.2: | 942 | braces@~3.0.2: |
932 | version "3.0.2" | 943 | version "3.0.2" |
933 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" | 944 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" |
934 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== | 945 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== |
@@ -980,11 +991,6 @@ bufferutil@^4.0.0: | |||
980 | dependencies: | 991 | dependencies: |
981 | node-gyp-build "~3.7.0" | 992 | node-gyp-build "~3.7.0" |
982 | 993 | ||
983 | builtin-modules@^1.1.1: | ||
984 | version "1.1.1" | ||
985 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" | ||
986 | integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= | ||
987 | |||
988 | bull@^3.4.2: | 994 | bull@^3.4.2: |
989 | version "3.12.1" | 995 | version "3.12.1" |
990 | resolved "https://registry.yarnpkg.com/bull/-/bull-3.12.1.tgz#ced62d0afca81c9264b44f1b6f39243df5d2e73f" | 996 | resolved "https://registry.yarnpkg.com/bull/-/bull-3.12.1.tgz#ced62d0afca81c9264b44f1b6f39243df5d2e73f" |
@@ -1019,29 +1025,15 @@ call-me-maybe@^1.0.1: | |||
1019 | resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" | 1025 | resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" |
1020 | integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= | 1026 | integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= |
1021 | 1027 | ||
1022 | caller-callsite@^2.0.0: | ||
1023 | version "2.0.0" | ||
1024 | resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" | ||
1025 | integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= | ||
1026 | dependencies: | ||
1027 | callsites "^2.0.0" | ||
1028 | |||
1029 | caller-path@^2.0.0: | ||
1030 | version "2.0.0" | ||
1031 | resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" | ||
1032 | integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= | ||
1033 | dependencies: | ||
1034 | caller-callsite "^2.0.0" | ||
1035 | |||
1036 | callsite@1.0.0: | 1028 | callsite@1.0.0: |
1037 | version "1.0.0" | 1029 | version "1.0.0" |
1038 | resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" | 1030 | resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" |
1039 | integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= | 1031 | integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= |
1040 | 1032 | ||
1041 | callsites@^2.0.0: | 1033 | callsites@^3.0.0: |
1042 | version "2.0.0" | 1034 | version "3.1.0" |
1043 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" | 1035 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" |
1044 | integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= | 1036 | integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== |
1045 | 1037 | ||
1046 | camelcase@^4.0.0: | 1038 | camelcase@^4.0.0: |
1047 | version "4.1.0" | 1039 | version "4.1.0" |
@@ -1109,18 +1101,7 @@ chai@^4.1.1: | |||
1109 | pathval "^1.1.0" | 1101 | pathval "^1.1.0" |
1110 | type-detect "^4.0.5" | 1102 | type-detect "^4.0.5" |
1111 | 1103 | ||
1112 | chalk@^1.0.0, chalk@^1.1.3: | 1104 | chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2: |
1113 | version "1.1.3" | ||
1114 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" | ||
1115 | integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= | ||
1116 | dependencies: | ||
1117 | ansi-styles "^2.2.1" | ||
1118 | escape-string-regexp "^1.0.2" | ||
1119 | has-ansi "^2.0.0" | ||
1120 | strip-ansi "^3.0.0" | ||
1121 | supports-color "^2.0.0" | ||
1122 | |||
1123 | chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: | ||
1124 | version "2.4.2" | 1105 | version "2.4.2" |
1125 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" | 1106 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" |
1126 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== | 1107 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== |
@@ -1137,6 +1118,11 @@ chalk@^3.0.0: | |||
1137 | ansi-styles "^4.1.0" | 1118 | ansi-styles "^4.1.0" |
1138 | supports-color "^7.1.0" | 1119 | supports-color "^7.1.0" |
1139 | 1120 | ||
1121 | chardet@^0.7.0: | ||
1122 | version "0.7.0" | ||
1123 | resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" | ||
1124 | integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== | ||
1125 | |||
1140 | charenc@~0.0.1: | 1126 | charenc@~0.0.1: |
1141 | version "0.0.2" | 1127 | version "0.0.2" |
1142 | resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" | 1128 | resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" |
@@ -1234,30 +1220,22 @@ circular-json@^0.5.9: | |||
1234 | resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" | 1220 | resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" |
1235 | integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== | 1221 | integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== |
1236 | 1222 | ||
1237 | clean-stack@^2.0.0: | ||
1238 | version "2.2.0" | ||
1239 | resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" | ||
1240 | integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== | ||
1241 | |||
1242 | cli-boxes@^1.0.0: | 1223 | cli-boxes@^1.0.0: |
1243 | version "1.0.0" | 1224 | version "1.0.0" |
1244 | resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" | 1225 | resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" |
1245 | integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= | 1226 | integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= |
1246 | 1227 | ||
1247 | cli-cursor@^2.0.0, cli-cursor@^2.1.0: | 1228 | cli-cursor@^3.1.0: |
1248 | version "2.1.0" | 1229 | version "3.1.0" |
1249 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" | 1230 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" |
1250 | integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= | 1231 | integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== |
1251 | dependencies: | 1232 | dependencies: |
1252 | restore-cursor "^2.0.0" | 1233 | restore-cursor "^3.1.0" |
1253 | 1234 | ||
1254 | cli-truncate@^0.2.1: | 1235 | cli-width@^2.0.0: |
1255 | version "0.2.1" | 1236 | version "2.2.0" |
1256 | resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-0.2.1.tgz#9f15cfbb0705005369216c626ac7d05ab90dd574" | 1237 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" |
1257 | integrity sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ= | 1238 | integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= |
1258 | dependencies: | ||
1259 | slice-ansi "0.0.4" | ||
1260 | string-width "^1.0.1" | ||
1261 | 1239 | ||
1262 | cliui@^5.0.0: | 1240 | cliui@^5.0.0: |
1263 | version "5.0.0" | 1241 | version "5.0.0" |
@@ -1386,7 +1364,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: | |||
1386 | dependencies: | 1364 | dependencies: |
1387 | delayed-stream "~1.0.0" | 1365 | delayed-stream "~1.0.0" |
1388 | 1366 | ||
1389 | commander@^2.12.1, commander@^2.20.0, commander@^2.7.1: | 1367 | commander@^2.20.0, commander@^2.7.1: |
1390 | version "2.20.3" | 1368 | version "2.20.3" |
1391 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" | 1369 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" |
1392 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== | 1370 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== |
@@ -1439,9 +1417,9 @@ concat-stream@^1.5.2: | |||
1439 | typedarray "^0.0.6" | 1417 | typedarray "^0.0.6" |
1440 | 1418 | ||
1441 | concurrently@^5.0.0: | 1419 | concurrently@^5.0.0: |
1442 | version "5.0.2" | 1420 | version "5.1.0" |
1443 | resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-5.0.2.tgz#4d2911018c0f15ddec34a8e668fc48dced7f3b1e" | 1421 | resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-5.1.0.tgz#05523986ba7aaf4b58a49ddd658fab88fa783132" |
1444 | integrity sha512-iUNVI6PzKO0RVXV9pHWM0khvEbELxf3XLIoChaV6hHyoIaJuxQWZiOwlNysnJX5khsfvIK66+OJqRdbYrdsR1g== | 1422 | integrity sha512-9ViZMu3OOCID3rBgU31mjBftro2chOop0G2u1olq1OuwRBVRw/GxHTg80TVJBUTJfoswMmEUeuOg1g1yu1X2dA== |
1445 | dependencies: | 1423 | dependencies: |
1446 | chalk "^2.4.2" | 1424 | chalk "^2.4.2" |
1447 | date-fns "^2.0.1" | 1425 | date-fns "^2.0.1" |
@@ -1454,9 +1432,9 @@ concurrently@^5.0.0: | |||
1454 | yargs "^13.3.0" | 1432 | yargs "^13.3.0" |
1455 | 1433 | ||
1456 | config@^3.0.0: | 1434 | config@^3.0.0: |
1457 | version "3.2.4" | 1435 | version "3.2.5" |
1458 | resolved "https://registry.yarnpkg.com/config/-/config-3.2.4.tgz#e60a908582991e800852f9cb60fcf424f3274a6c" | 1436 | resolved "https://registry.yarnpkg.com/config/-/config-3.2.5.tgz#ab10ab88b61a873fbf9a5f0c6b4a22750422f243" |
1459 | integrity sha512-H1XIGfnU1EAkfjSLn9ZvYDRx9lOezDViuzLDgiJ/lMeqjYe3q6iQfpcLt2NInckJgpAeekbNhQkmnnbdEDs9rw== | 1437 | integrity sha512-8itpjyR01lAJanhAlPncBngYRZez/LoRLW8wnGi+6SEcsUyA1wvHvbpIrAJYDJT+W9BScnj4mYoUgbtp9I+0+Q== |
1460 | dependencies: | 1438 | dependencies: |
1461 | json5 "^1.0.1" | 1439 | json5 "^1.0.1" |
1462 | 1440 | ||
@@ -1477,6 +1455,11 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: | |||
1477 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" | 1455 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" |
1478 | integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= | 1456 | integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= |
1479 | 1457 | ||
1458 | contains-path@^0.1.0: | ||
1459 | version "0.1.0" | ||
1460 | resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" | ||
1461 | integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= | ||
1462 | |||
1480 | content-disposition@0.5.3: | 1463 | content-disposition@0.5.3: |
1481 | version "0.5.3" | 1464 | version "0.5.3" |
1482 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" | 1465 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" |
@@ -1535,16 +1518,6 @@ cors@^2.8.1, cors@^2.8.5: | |||
1535 | object-assign "^4" | 1518 | object-assign "^4" |
1536 | vary "^1" | 1519 | vary "^1" |
1537 | 1520 | ||
1538 | cosmiconfig@^5.2.1: | ||
1539 | version "5.2.1" | ||
1540 | resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" | ||
1541 | integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== | ||
1542 | dependencies: | ||
1543 | import-fresh "^2.0.0" | ||
1544 | is-directory "^0.3.1" | ||
1545 | js-yaml "^3.13.1" | ||
1546 | parse-json "^4.0.0" | ||
1547 | |||
1548 | create-error-class@^3.0.0: | 1521 | create-error-class@^3.0.0: |
1549 | version "3.0.2" | 1522 | version "3.0.2" |
1550 | resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" | 1523 | resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" |
@@ -1587,6 +1560,17 @@ cross-spawn@^5.0.1: | |||
1587 | shebang-command "^1.2.0" | 1560 | shebang-command "^1.2.0" |
1588 | which "^1.2.9" | 1561 | which "^1.2.9" |
1589 | 1562 | ||
1563 | cross-spawn@^6.0.5: | ||
1564 | version "6.0.5" | ||
1565 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" | ||
1566 | integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== | ||
1567 | dependencies: | ||
1568 | nice-try "^1.0.4" | ||
1569 | path-key "^2.0.1" | ||
1570 | semver "^5.5.0" | ||
1571 | shebang-command "^1.2.0" | ||
1572 | which "^1.2.9" | ||
1573 | |||
1590 | cross-spawn@^7.0.0: | 1574 | cross-spawn@^7.0.0: |
1591 | version "7.0.1" | 1575 | version "7.0.1" |
1592 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" | 1576 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" |
@@ -1631,17 +1615,12 @@ dasherize@2.0.0: | |||
1631 | resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308" | 1615 | resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308" |
1632 | integrity sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg= | 1616 | integrity sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg= |
1633 | 1617 | ||
1634 | date-fns@^1.27.2: | ||
1635 | version "1.30.1" | ||
1636 | resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c" | ||
1637 | integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw== | ||
1638 | |||
1639 | date-fns@^2.0.1: | 1618 | date-fns@^2.0.1: |
1640 | version "2.8.1" | 1619 | version "2.9.0" |
1641 | resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.8.1.tgz#2109362ccb6c87c3ca011e9e31f702bc09e4123b" | 1620 | resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.9.0.tgz#d0b175a5c37ed5f17b97e2272bbc1fa5aec677d2" |
1642 | integrity sha512-EL/C8IHvYRwAHYgFRse4MGAPSqlJVlOrhVYZ75iQBKrnv+ZedmYsgwH3t+BCDuZDXpoo07+q9j4qgSSOa7irJg== | 1621 | integrity sha512-khbFLu/MlzLjEzy9Gh8oY1hNt/Dvxw3J6Rbc28cVoYWQaC1S3YI4xwkF9ZWcjDLscbZlY9hISMr66RFzZagLsA== |
1643 | 1622 | ||
1644 | debug@2.6.9, debug@^2.2.0: | 1623 | debug@2.6.9, debug@^2.2.0, debug@^2.6.9: |
1645 | version "2.6.9" | 1624 | version "2.6.9" |
1646 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" | 1625 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" |
1647 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== | 1626 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== |
@@ -1686,11 +1665,6 @@ decompress-response@^4.2.0: | |||
1686 | dependencies: | 1665 | dependencies: |
1687 | mimic-response "^2.0.0" | 1666 | mimic-response "^2.0.0" |
1688 | 1667 | ||
1689 | dedent@^0.7.0: | ||
1690 | version "0.7.0" | ||
1691 | resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" | ||
1692 | integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= | ||
1693 | |||
1694 | deep-eql@0.1.3: | 1668 | deep-eql@0.1.3: |
1695 | version "0.1.3" | 1669 | version "0.1.3" |
1696 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" | 1670 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" |
@@ -1715,6 +1689,11 @@ deep-extend@^0.6.0: | |||
1715 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" | 1689 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" |
1716 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== | 1690 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== |
1717 | 1691 | ||
1692 | deep-is@~0.1.3: | ||
1693 | version "0.1.3" | ||
1694 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" | ||
1695 | integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= | ||
1696 | |||
1718 | deep-object-diff@^1.1.0: | 1697 | deep-object-diff@^1.1.0: |
1719 | version "1.1.0" | 1698 | version "1.1.0" |
1720 | resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a" | 1699 | resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a" |
@@ -1727,20 +1706,6 @@ define-properties@^1.1.2, define-properties@^1.1.3: | |||
1727 | dependencies: | 1706 | dependencies: |
1728 | object-keys "^1.0.12" | 1707 | object-keys "^1.0.12" |
1729 | 1708 | ||
1730 | del@^5.0.0: | ||
1731 | version "5.1.0" | ||
1732 | resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7" | ||
1733 | integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA== | ||
1734 | dependencies: | ||
1735 | globby "^10.0.1" | ||
1736 | graceful-fs "^4.2.2" | ||
1737 | is-glob "^4.0.1" | ||
1738 | is-path-cwd "^2.2.0" | ||
1739 | is-path-inside "^3.0.1" | ||
1740 | p-map "^3.0.0" | ||
1741 | rimraf "^3.0.0" | ||
1742 | slash "^3.0.0" | ||
1743 | |||
1744 | delayed-stream@~1.0.0: | 1709 | delayed-stream@~1.0.0: |
1745 | version "1.0.0" | 1710 | version "1.0.0" |
1746 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" | 1711 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" |
@@ -1799,29 +1764,29 @@ diff@3.5.0: | |||
1799 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== | 1764 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== |
1800 | 1765 | ||
1801 | diff@^4.0.1: | 1766 | diff@^4.0.1: |
1802 | version "4.0.1" | 1767 | version "4.0.2" |
1803 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff" | 1768 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" |
1804 | integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q== | 1769 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== |
1805 | |||
1806 | dir-glob@^3.0.1: | ||
1807 | version "3.0.1" | ||
1808 | resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" | ||
1809 | integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== | ||
1810 | dependencies: | ||
1811 | path-type "^4.0.0" | ||
1812 | 1770 | ||
1813 | dns-prefetch-control@0.2.0: | 1771 | dns-prefetch-control@0.2.0: |
1814 | version "0.2.0" | 1772 | version "0.2.0" |
1815 | resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz#73988161841f3dcc81f47686d539a2c702c88624" | 1773 | resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz#73988161841f3dcc81f47686d539a2c702c88624" |
1816 | integrity sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q== | 1774 | integrity sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q== |
1817 | 1775 | ||
1818 | doctrine@0.7.2: | 1776 | doctrine@1.5.0: |
1819 | version "0.7.2" | 1777 | version "1.5.0" |
1820 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523" | 1778 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" |
1821 | integrity sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM= | 1779 | integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= |
1822 | dependencies: | 1780 | dependencies: |
1823 | esutils "^1.1.6" | 1781 | esutils "^2.0.2" |
1824 | isarray "0.0.1" | 1782 | isarray "^1.0.0" |
1783 | |||
1784 | doctrine@^3.0.0: | ||
1785 | version "3.0.0" | ||
1786 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" | ||
1787 | integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== | ||
1788 | dependencies: | ||
1789 | esutils "^2.0.2" | ||
1825 | 1790 | ||
1826 | dont-sniff-mimetype@1.1.0: | 1791 | dont-sniff-mimetype@1.1.0: |
1827 | version "1.1.0" | 1792 | version "1.1.0" |
@@ -1873,11 +1838,6 @@ ee-first@1.1.1: | |||
1873 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" | 1838 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" |
1874 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= | 1839 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= |
1875 | 1840 | ||
1876 | elegant-spinner@^1.0.1: | ||
1877 | version "1.0.1" | ||
1878 | resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" | ||
1879 | integrity sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4= | ||
1880 | |||
1881 | emoji-regex@^7.0.1: | 1841 | emoji-regex@^7.0.1: |
1882 | version "7.0.3" | 1842 | version "7.0.3" |
1883 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" | 1843 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" |
@@ -1988,21 +1948,21 @@ engine.io@~3.4.0: | |||
1988 | ws "^7.1.2" | 1948 | ws "^7.1.2" |
1989 | 1949 | ||
1990 | env-variable@0.0.x: | 1950 | env-variable@0.0.x: |
1991 | version "0.0.5" | 1951 | version "0.0.6" |
1992 | resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88" | 1952 | resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.6.tgz#74ab20b3786c545b62b4a4813ab8cf22726c9808" |
1993 | integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA== | 1953 | integrity sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg== |
1994 | 1954 | ||
1995 | error-ex@^1.3.1: | 1955 | error-ex@^1.2.0, error-ex@^1.3.1: |
1996 | version "1.3.2" | 1956 | version "1.3.2" |
1997 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" | 1957 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" |
1998 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== | 1958 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== |
1999 | dependencies: | 1959 | dependencies: |
2000 | is-arrayish "^0.2.1" | 1960 | is-arrayish "^0.2.1" |
2001 | 1961 | ||
2002 | es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1: | 1962 | es-abstract@^1.17.0, es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: |
2003 | version "1.17.0" | 1963 | version "1.17.4" |
2004 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.0.tgz#f42a517d0036a5591dbb2c463591dc8bb50309b1" | 1964 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184" |
2005 | integrity sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug== | 1965 | integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ== |
2006 | dependencies: | 1966 | dependencies: |
2007 | es-to-primitive "^1.2.1" | 1967 | es-to-primitive "^1.2.1" |
2008 | function-bind "^1.1.1" | 1968 | function-bind "^1.1.1" |
@@ -2071,20 +2031,190 @@ escape-html@^1.0.3, escape-html@~1.0.3: | |||
2071 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" | 2031 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" |
2072 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= | 2032 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= |
2073 | 2033 | ||
2074 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5, escape-string-regexp@~1.0.5: | 2034 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5, escape-string-regexp@~1.0.5: |
2075 | version "1.0.5" | 2035 | version "1.0.5" |
2076 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" | 2036 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" |
2077 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= | 2037 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= |
2078 | 2038 | ||
2039 | eslint-config-standard-with-typescript@^12.0.1: | ||
2040 | version "12.0.1" | ||
2041 | resolved "https://registry.yarnpkg.com/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-12.0.1.tgz#60f941a3a942b50393715ca336e1c7ba76e3ab04" | ||
2042 | integrity sha512-v0DDNzsb36Oun3N04Y27Ca9DfF+S9Orrdtqa5anUUpwIu/MMqCRxYAcKdD0Uao+Gzqz9EjaFYjBKZCPFyXH5jw== | ||
2043 | dependencies: | ||
2044 | "@typescript-eslint/parser" "^2.10.0" | ||
2045 | eslint-config-standard "^14.1.0" | ||
2046 | |||
2047 | eslint-config-standard@^14.1.0: | ||
2048 | version "14.1.0" | ||
2049 | resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.0.tgz#b23da2b76fe5a2eba668374f246454e7058f15d4" | ||
2050 | integrity sha512-EF6XkrrGVbvv8hL/kYa/m6vnvmUT+K82pJJc4JJVMM6+Qgqh0pnwprSxdduDLB9p/7bIxD+YV5O0wfb8lmcPbA== | ||
2051 | |||
2052 | eslint-import-resolver-node@^0.3.2: | ||
2053 | version "0.3.3" | ||
2054 | resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404" | ||
2055 | integrity sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg== | ||
2056 | dependencies: | ||
2057 | debug "^2.6.9" | ||
2058 | resolve "^1.13.1" | ||
2059 | |||
2060 | eslint-module-utils@^2.4.1: | ||
2061 | version "2.5.2" | ||
2062 | resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz#7878f7504824e1b857dd2505b59a8e5eda26a708" | ||
2063 | integrity sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q== | ||
2064 | dependencies: | ||
2065 | debug "^2.6.9" | ||
2066 | pkg-dir "^2.0.0" | ||
2067 | |||
2068 | eslint-plugin-es@^3.0.0: | ||
2069 | version "3.0.0" | ||
2070 | resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.0.tgz#98cb1bc8ab0aa807977855e11ad9d1c9422d014b" | ||
2071 | integrity sha512-6/Jb/J/ZvSebydwbBJO1R9E5ky7YeElfK56Veh7e4QGFHCXoIXGH9HhVz+ibJLM3XJ1XjP+T7rKBLUa/Y7eIng== | ||
2072 | dependencies: | ||
2073 | eslint-utils "^2.0.0" | ||
2074 | regexpp "^3.0.0" | ||
2075 | |||
2076 | eslint-plugin-import@^2.20.1: | ||
2077 | version "2.20.1" | ||
2078 | resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz#802423196dcb11d9ce8435a5fc02a6d3b46939b3" | ||
2079 | integrity sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw== | ||
2080 | dependencies: | ||
2081 | array-includes "^3.0.3" | ||
2082 | array.prototype.flat "^1.2.1" | ||
2083 | contains-path "^0.1.0" | ||
2084 | debug "^2.6.9" | ||
2085 | doctrine "1.5.0" | ||
2086 | eslint-import-resolver-node "^0.3.2" | ||
2087 | eslint-module-utils "^2.4.1" | ||
2088 | has "^1.0.3" | ||
2089 | minimatch "^3.0.4" | ||
2090 | object.values "^1.1.0" | ||
2091 | read-pkg-up "^2.0.0" | ||
2092 | resolve "^1.12.0" | ||
2093 | |||
2094 | eslint-plugin-node@^11.0.0: | ||
2095 | version "11.0.0" | ||
2096 | resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.0.0.tgz#365944bb0804c5d1d501182a9bc41a0ffefed726" | ||
2097 | integrity sha512-chUs/NVID+sknFiJzxoN9lM7uKSOEta8GC8365hw1nDfwIPIjjpRSwwPvQanWv8dt/pDe9EV4anmVSwdiSndNg== | ||
2098 | dependencies: | ||
2099 | eslint-plugin-es "^3.0.0" | ||
2100 | eslint-utils "^2.0.0" | ||
2101 | ignore "^5.1.1" | ||
2102 | minimatch "^3.0.4" | ||
2103 | resolve "^1.10.1" | ||
2104 | semver "^6.1.0" | ||
2105 | |||
2106 | eslint-plugin-promise@^4.2.1: | ||
2107 | version "4.2.1" | ||
2108 | resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a" | ||
2109 | integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw== | ||
2110 | |||
2111 | eslint-plugin-standard@^4.0.1: | ||
2112 | version "4.0.1" | ||
2113 | resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4" | ||
2114 | integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ== | ||
2115 | |||
2116 | eslint-scope@^5.0.0: | ||
2117 | version "5.0.0" | ||
2118 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" | ||
2119 | integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== | ||
2120 | dependencies: | ||
2121 | esrecurse "^4.1.0" | ||
2122 | estraverse "^4.1.1" | ||
2123 | |||
2124 | eslint-utils@^1.4.3: | ||
2125 | version "1.4.3" | ||
2126 | resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" | ||
2127 | integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== | ||
2128 | dependencies: | ||
2129 | eslint-visitor-keys "^1.1.0" | ||
2130 | |||
2131 | eslint-utils@^2.0.0: | ||
2132 | version "2.0.0" | ||
2133 | resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd" | ||
2134 | integrity sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA== | ||
2135 | dependencies: | ||
2136 | eslint-visitor-keys "^1.1.0" | ||
2137 | |||
2138 | eslint-visitor-keys@^1.1.0: | ||
2139 | version "1.1.0" | ||
2140 | resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" | ||
2141 | integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== | ||
2142 | |||
2143 | eslint@^6.8.0: | ||
2144 | version "6.8.0" | ||
2145 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" | ||
2146 | integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== | ||
2147 | dependencies: | ||
2148 | "@babel/code-frame" "^7.0.0" | ||
2149 | ajv "^6.10.0" | ||
2150 | chalk "^2.1.0" | ||
2151 | cross-spawn "^6.0.5" | ||
2152 | debug "^4.0.1" | ||
2153 | doctrine "^3.0.0" | ||
2154 | eslint-scope "^5.0.0" | ||
2155 | eslint-utils "^1.4.3" | ||
2156 | eslint-visitor-keys "^1.1.0" | ||
2157 | espree "^6.1.2" | ||
2158 | esquery "^1.0.1" | ||
2159 | esutils "^2.0.2" | ||
2160 | file-entry-cache "^5.0.1" | ||
2161 | functional-red-black-tree "^1.0.1" | ||
2162 | glob-parent "^5.0.0" | ||
2163 | globals "^12.1.0" | ||
2164 | ignore "^4.0.6" | ||
2165 | import-fresh "^3.0.0" | ||
2166 | imurmurhash "^0.1.4" | ||
2167 | inquirer "^7.0.0" | ||
2168 | is-glob "^4.0.0" | ||
2169 | js-yaml "^3.13.1" | ||
2170 | json-stable-stringify-without-jsonify "^1.0.1" | ||
2171 | levn "^0.3.0" | ||
2172 | lodash "^4.17.14" | ||
2173 | minimatch "^3.0.4" | ||
2174 | mkdirp "^0.5.1" | ||
2175 | natural-compare "^1.4.0" | ||
2176 | optionator "^0.8.3" | ||
2177 | progress "^2.0.0" | ||
2178 | regexpp "^2.0.1" | ||
2179 | semver "^6.1.2" | ||
2180 | strip-ansi "^5.2.0" | ||
2181 | strip-json-comments "^3.0.1" | ||
2182 | table "^5.2.3" | ||
2183 | text-table "^0.2.0" | ||
2184 | v8-compile-cache "^2.0.3" | ||
2185 | |||
2186 | espree@^6.1.2: | ||
2187 | version "6.1.2" | ||
2188 | resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.2.tgz#6c272650932b4f91c3714e5e7b5f5e2ecf47262d" | ||
2189 | integrity sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA== | ||
2190 | dependencies: | ||
2191 | acorn "^7.1.0" | ||
2192 | acorn-jsx "^5.1.0" | ||
2193 | eslint-visitor-keys "^1.1.0" | ||
2194 | |||
2079 | esprima@^4.0.0: | 2195 | esprima@^4.0.0: |
2080 | version "4.0.1" | 2196 | version "4.0.1" |
2081 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" | 2197 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" |
2082 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== | 2198 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== |
2083 | 2199 | ||
2084 | esutils@^1.1.6: | 2200 | esquery@^1.0.1: |
2085 | version "1.1.6" | 2201 | version "1.0.1" |
2086 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-1.1.6.tgz#c01ccaa9ae4b897c6d0c3e210ae52f3c7a844375" | 2202 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" |
2087 | integrity sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U= | 2203 | integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== |
2204 | dependencies: | ||
2205 | estraverse "^4.0.0" | ||
2206 | |||
2207 | esrecurse@^4.1.0: | ||
2208 | version "4.2.1" | ||
2209 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" | ||
2210 | integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== | ||
2211 | dependencies: | ||
2212 | estraverse "^4.1.0" | ||
2213 | |||
2214 | estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: | ||
2215 | version "4.3.0" | ||
2216 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" | ||
2217 | integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== | ||
2088 | 2218 | ||
2089 | esutils@^2.0.2: | 2219 | esutils@^2.0.2: |
2090 | version "2.0.3" | 2220 | version "2.0.3" |
@@ -2117,21 +2247,6 @@ execa@^0.7.0: | |||
2117 | signal-exit "^3.0.0" | 2247 | signal-exit "^3.0.0" |
2118 | strip-eof "^1.0.0" | 2248 | strip-eof "^1.0.0" |
2119 | 2249 | ||
2120 | execa@^2.0.3: | ||
2121 | version "2.1.0" | ||
2122 | resolved "https://registry.yarnpkg.com/execa/-/execa-2.1.0.tgz#e5d3ecd837d2a60ec50f3da78fd39767747bbe99" | ||
2123 | integrity sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw== | ||
2124 | dependencies: | ||
2125 | cross-spawn "^7.0.0" | ||
2126 | get-stream "^5.0.0" | ||
2127 | is-stream "^2.0.0" | ||
2128 | merge-stream "^2.0.0" | ||
2129 | npm-run-path "^3.0.0" | ||
2130 | onetime "^5.1.0" | ||
2131 | p-finally "^2.0.0" | ||
2132 | signal-exit "^3.0.2" | ||
2133 | strip-final-newline "^2.0.0" | ||
2134 | |||
2135 | execa@~3.2.0: | 2250 | execa@~3.2.0: |
2136 | version "3.2.0" | 2251 | version "3.2.0" |
2137 | resolved "https://registry.yarnpkg.com/execa/-/execa-3.2.0.tgz#18326b79c7ab7fbd6610fd900c1b9e95fa48f90a" | 2252 | resolved "https://registry.yarnpkg.com/execa/-/execa-3.2.0.tgz#18326b79c7ab7fbd6610fd900c1b9e95fa48f90a" |
@@ -2172,13 +2287,13 @@ express-rate-limit@^4.0.4: | |||
2172 | resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-4.0.4.tgz#a495338ae9e58c856b66d1346ec0d86f43ba2e43" | 2287 | resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-4.0.4.tgz#a495338ae9e58c856b66d1346ec0d86f43ba2e43" |
2173 | integrity sha512-DLRj2vMO7Xgai8qWKU9O6ZztF2bdDmfFNFi9k3G9BPzJ+7MG7eWaaBikbe0eBpNGSxU8JziwW0PQKG78aNWa6g== | 2288 | integrity sha512-DLRj2vMO7Xgai8qWKU9O6ZztF2bdDmfFNFi9k3G9BPzJ+7MG7eWaaBikbe0eBpNGSxU8JziwW0PQKG78aNWa6g== |
2174 | 2289 | ||
2175 | express-validator@^6.1.1: | 2290 | express-validator@^6.4.0: |
2176 | version "6.3.1" | 2291 | version "6.4.0" |
2177 | resolved "https://registry.yarnpkg.com/express-validator/-/express-validator-6.3.1.tgz#5ad6ca3ce6141f33638608d006d26c217500f375" | 2292 | resolved "https://registry.yarnpkg.com/express-validator/-/express-validator-6.4.0.tgz#634f96b60d53112409e270c038ab818a36f56e47" |
2178 | integrity sha512-YQHQKP/zlUTN6d38uWwXgK3At5phK6R24pOB/ImWisMUz/U/1AC3ZXMgiZYhtH4ViYJ6UAiV0/nj8s1Qs3kmvw== | 2293 | integrity sha512-Fs+x0yDOSiUV+o5jIRloMyBxqpSzJiMM8KQW1IRVv2l49F6ATU0F9uPa+3K6vXNlLlhUjauv2FCGLFPMaNr24w== |
2179 | dependencies: | 2294 | dependencies: |
2180 | lodash "^4.17.15" | 2295 | lodash "^4.17.15" |
2181 | validator "^11.1.0" | 2296 | validator "^12.1.0" |
2182 | 2297 | ||
2183 | express@^4.12.4, express@^4.13.3, express@^4.17.1: | 2298 | express@^4.12.4, express@^4.13.3, express@^4.17.1: |
2184 | version "4.17.1" | 2299 | version "4.17.1" |
@@ -2228,6 +2343,15 @@ extend@^3.0.0, extend@~3.0.0, extend@~3.0.2: | |||
2228 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" | 2343 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" |
2229 | integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== | 2344 | integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== |
2230 | 2345 | ||
2346 | external-editor@^3.0.3: | ||
2347 | version "3.1.0" | ||
2348 | resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" | ||
2349 | integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== | ||
2350 | dependencies: | ||
2351 | chardet "^0.7.0" | ||
2352 | iconv-lite "^0.4.24" | ||
2353 | tmp "^0.0.33" | ||
2354 | |||
2231 | extsprintf@1.3.0: | 2355 | extsprintf@1.3.0: |
2232 | version "1.3.0" | 2356 | version "1.3.0" |
2233 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" | 2357 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" |
@@ -2243,39 +2367,26 @@ eyes@0.1.x: | |||
2243 | resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" | 2367 | resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" |
2244 | integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= | 2368 | integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= |
2245 | 2369 | ||
2246 | fast-deep-equal@^2.0.1: | 2370 | fast-deep-equal@^3.1.1: |
2247 | version "2.0.1" | ||
2248 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" | ||
2249 | integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= | ||
2250 | |||
2251 | fast-glob@^3.0.3: | ||
2252 | version "3.1.1" | 2371 | version "3.1.1" |
2253 | resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.1.1.tgz#87ee30e9e9f3eb40d6f254a7997655da753d7c82" | 2372 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" |
2254 | integrity sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g== | 2373 | integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== |
2255 | dependencies: | ||
2256 | "@nodelib/fs.stat" "^2.0.2" | ||
2257 | "@nodelib/fs.walk" "^1.2.3" | ||
2258 | glob-parent "^5.1.0" | ||
2259 | merge2 "^1.3.0" | ||
2260 | micromatch "^4.0.2" | ||
2261 | 2374 | ||
2262 | fast-json-stable-stringify@^2.0.0: | 2375 | fast-json-stable-stringify@^2.0.0: |
2263 | version "2.1.0" | 2376 | version "2.1.0" |
2264 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" | 2377 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" |
2265 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== | 2378 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== |
2266 | 2379 | ||
2380 | fast-levenshtein@~2.0.6: | ||
2381 | version "2.0.6" | ||
2382 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" | ||
2383 | integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= | ||
2384 | |||
2267 | fast-safe-stringify@^2.0.4: | 2385 | fast-safe-stringify@^2.0.4: |
2268 | version "2.0.7" | 2386 | version "2.0.7" |
2269 | resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" | 2387 | resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" |
2270 | integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== | 2388 | integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== |
2271 | 2389 | ||
2272 | fastq@^1.6.0: | ||
2273 | version "1.6.0" | ||
2274 | resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.6.0.tgz#4ec8a38f4ac25f21492673adb7eae9cfef47d1c2" | ||
2275 | integrity sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA== | ||
2276 | dependencies: | ||
2277 | reusify "^1.0.0" | ||
2278 | |||
2279 | feature-policy@0.3.0: | 2390 | feature-policy@0.3.0: |
2280 | version "0.3.0" | 2391 | version "0.3.0" |
2281 | resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.3.0.tgz#7430e8e54a40da01156ca30aaec1a381ce536069" | 2392 | resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.3.0.tgz#7430e8e54a40da01156ca30aaec1a381ce536069" |
@@ -2286,20 +2397,19 @@ fecha@^2.3.3: | |||
2286 | resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd" | 2397 | resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd" |
2287 | integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg== | 2398 | integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg== |
2288 | 2399 | ||
2289 | figures@^1.7.0: | 2400 | figures@^3.0.0: |
2290 | version "1.7.0" | 2401 | version "3.1.0" |
2291 | resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" | 2402 | resolved "https://registry.yarnpkg.com/figures/-/figures-3.1.0.tgz#4b198dd07d8d71530642864af2d45dd9e459c4ec" |
2292 | integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= | 2403 | integrity sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg== |
2293 | dependencies: | 2404 | dependencies: |
2294 | escape-string-regexp "^1.0.5" | 2405 | escape-string-regexp "^1.0.5" |
2295 | object-assign "^4.1.0" | ||
2296 | 2406 | ||
2297 | figures@^2.0.0: | 2407 | file-entry-cache@^5.0.1: |
2298 | version "2.0.0" | 2408 | version "5.0.1" |
2299 | resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" | 2409 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" |
2300 | integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= | 2410 | integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== |
2301 | dependencies: | 2411 | dependencies: |
2302 | escape-string-regexp "^1.0.5" | 2412 | flat-cache "^2.0.1" |
2303 | 2413 | ||
2304 | filestream@^5.0.0: | 2414 | filestream@^5.0.0: |
2305 | version "5.0.0" | 2415 | version "5.0.0" |
@@ -2336,6 +2446,13 @@ find-up@3.0.0, find-up@^3.0.0: | |||
2336 | dependencies: | 2446 | dependencies: |
2337 | locate-path "^3.0.0" | 2447 | locate-path "^3.0.0" |
2338 | 2448 | ||
2449 | find-up@^2.0.0, find-up@^2.1.0: | ||
2450 | version "2.1.0" | ||
2451 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" | ||
2452 | integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= | ||
2453 | dependencies: | ||
2454 | locate-path "^2.0.0" | ||
2455 | |||
2339 | find-up@^4.1.0: | 2456 | find-up@^4.1.0: |
2340 | version "4.1.0" | 2457 | version "4.1.0" |
2341 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" | 2458 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" |
@@ -2344,6 +2461,15 @@ find-up@^4.1.0: | |||
2344 | locate-path "^5.0.0" | 2461 | locate-path "^5.0.0" |
2345 | path-exists "^4.0.0" | 2462 | path-exists "^4.0.0" |
2346 | 2463 | ||
2464 | flat-cache@^2.0.1: | ||
2465 | version "2.0.1" | ||
2466 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" | ||
2467 | integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== | ||
2468 | dependencies: | ||
2469 | flatted "^2.0.0" | ||
2470 | rimraf "2.6.3" | ||
2471 | write "1.0.3" | ||
2472 | |||
2347 | flat@^4.1.0: | 2473 | flat@^4.1.0: |
2348 | version "4.1.0" | 2474 | version "4.1.0" |
2349 | resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" | 2475 | resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" |
@@ -2358,6 +2484,11 @@ flat@^5.0.0: | |||
2358 | dependencies: | 2484 | dependencies: |
2359 | is-buffer "~2.0.4" | 2485 | is-buffer "~2.0.4" |
2360 | 2486 | ||
2487 | flatted@^2.0.0: | ||
2488 | version "2.0.1" | ||
2489 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" | ||
2490 | integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== | ||
2491 | |||
2361 | fluent-ffmpeg@^2.1.0: | 2492 | fluent-ffmpeg@^2.1.0: |
2362 | version "2.1.2" | 2493 | version "2.1.2" |
2363 | resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74" | 2494 | resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74" |
@@ -2447,9 +2578,9 @@ fs-minipass@^1.2.5: | |||
2447 | minipass "^2.6.0" | 2578 | minipass "^2.6.0" |
2448 | 2579 | ||
2449 | fs-minipass@^2.0.0: | 2580 | fs-minipass@^2.0.0: |
2450 | version "2.0.0" | 2581 | version "2.1.0" |
2451 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.0.0.tgz#a6415edab02fae4b9e9230bc87ee2e4472003cd1" | 2582 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" |
2452 | integrity sha512-40Qz+LFXmd9tzYVnnBmZvFfvAADfUA14TXPK1s7IfElJTIZ97rA8w4Kin7Wt5JBrC3ShnnFJO/5vPjPEeJIq9A== | 2583 | integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== |
2453 | dependencies: | 2584 | dependencies: |
2454 | minipass "^3.0.0" | 2585 | minipass "^3.0.0" |
2455 | 2586 | ||
@@ -2468,6 +2599,11 @@ function-bind@^1.1.1: | |||
2468 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" | 2599 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" |
2469 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== | 2600 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== |
2470 | 2601 | ||
2602 | functional-red-black-tree@^1.0.1: | ||
2603 | version "1.0.1" | ||
2604 | resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" | ||
2605 | integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= | ||
2606 | |||
2471 | gauge@~2.7.3: | 2607 | gauge@~2.7.3: |
2472 | version "2.7.4" | 2608 | version "2.7.4" |
2473 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" | 2609 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" |
@@ -2497,15 +2633,10 @@ get-func-name@^2.0.0: | |||
2497 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" | 2633 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" |
2498 | integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= | 2634 | integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= |
2499 | 2635 | ||
2500 | get-own-enumerable-property-symbols@^3.0.0: | ||
2501 | version "3.0.2" | ||
2502 | resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" | ||
2503 | integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== | ||
2504 | |||
2505 | get-port@^5.0.0: | 2636 | get-port@^5.0.0: |
2506 | version "5.1.0" | 2637 | version "5.1.1" |
2507 | resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.0.tgz#a8f6510d0000f07d5c65653a4b0ae648fe832683" | 2638 | resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" |
2508 | integrity sha512-bjioH1E9bTQUvgaB6VycVy1QVbTZI41yTnF9qkZz6ixgy/uhCH6D63bKeZ6Code/07JYA61MeI94jSdHss8PNA== | 2639 | integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== |
2509 | 2640 | ||
2510 | get-stdin@^7.0.0: | 2641 | get-stdin@^7.0.0: |
2511 | version "7.0.0" | 2642 | version "7.0.0" |
@@ -2536,7 +2667,7 @@ github-from-package@0.0.0: | |||
2536 | resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" | 2667 | resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" |
2537 | integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= | 2668 | integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= |
2538 | 2669 | ||
2539 | glob-parent@^5.1.0, glob-parent@~5.1.0: | 2670 | glob-parent@^5.0.0, glob-parent@~5.1.0: |
2540 | version "5.1.0" | 2671 | version "5.1.0" |
2541 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" | 2672 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" |
2542 | integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== | 2673 | integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== |
@@ -2567,7 +2698,7 @@ glob@7.1.3: | |||
2567 | once "^1.3.0" | 2698 | once "^1.3.0" |
2568 | path-is-absolute "^1.0.0" | 2699 | path-is-absolute "^1.0.0" |
2569 | 2700 | ||
2570 | glob@^7.0.3, glob@^7.1.1, glob@^7.1.3: | 2701 | glob@^7.0.3, glob@^7.1.3, glob@^7.1.6: |
2571 | version "7.1.6" | 2702 | version "7.1.6" |
2572 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" | 2703 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" |
2573 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== | 2704 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== |
@@ -2586,19 +2717,12 @@ global-dirs@^0.1.0: | |||
2586 | dependencies: | 2717 | dependencies: |
2587 | ini "^1.3.4" | 2718 | ini "^1.3.4" |
2588 | 2719 | ||
2589 | globby@^10.0.1: | 2720 | globals@^12.1.0: |
2590 | version "10.0.2" | 2721 | version "12.3.0" |
2591 | resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" | 2722 | resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13" |
2592 | integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== | 2723 | integrity sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw== |
2593 | dependencies: | 2724 | dependencies: |
2594 | "@types/glob" "^7.1.1" | 2725 | type-fest "^0.8.1" |
2595 | array-union "^2.1.0" | ||
2596 | dir-glob "^3.0.1" | ||
2597 | fast-glob "^3.0.3" | ||
2598 | glob "^7.1.3" | ||
2599 | ignore "^5.1.1" | ||
2600 | merge2 "^1.2.3" | ||
2601 | slash "^3.0.0" | ||
2602 | 2726 | ||
2603 | got@^6.7.1: | 2727 | got@^6.7.1: |
2604 | version "6.7.1" | 2728 | version "6.7.1" |
@@ -2617,7 +2741,7 @@ got@^6.7.1: | |||
2617 | unzip-response "^2.0.1" | 2741 | unzip-response "^2.0.1" |
2618 | url-parse-lax "^1.0.0" | 2742 | url-parse-lax "^1.0.0" |
2619 | 2743 | ||
2620 | graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2: | 2744 | graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: |
2621 | version "4.2.3" | 2745 | version "4.2.3" |
2622 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" | 2746 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" |
2623 | integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== | 2747 | integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== |
@@ -2640,13 +2764,6 @@ har-validator@~5.1.0: | |||
2640 | ajv "^6.5.5" | 2764 | ajv "^6.5.5" |
2641 | har-schema "^2.0.0" | 2765 | har-schema "^2.0.0" |
2642 | 2766 | ||
2643 | has-ansi@^2.0.0: | ||
2644 | version "2.0.0" | ||
2645 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" | ||
2646 | integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= | ||
2647 | dependencies: | ||
2648 | ansi-regex "^2.0.0" | ||
2649 | |||
2650 | has-binary2@~1.0.2: | 2767 | has-binary2@~1.0.2: |
2651 | version "1.0.3" | 2768 | version "1.0.3" |
2652 | resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" | 2769 | resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" |
@@ -2826,7 +2943,7 @@ i@0.3.x: | |||
2826 | resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" | 2943 | resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" |
2827 | integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0= | 2944 | integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0= |
2828 | 2945 | ||
2829 | iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.24: | 2946 | iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.24: |
2830 | version "0.4.24" | 2947 | version "0.4.24" |
2831 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" | 2948 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" |
2832 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== | 2949 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== |
@@ -2850,6 +2967,11 @@ ignore-walk@^3.0.1: | |||
2850 | dependencies: | 2967 | dependencies: |
2851 | minimatch "^3.0.4" | 2968 | minimatch "^3.0.4" |
2852 | 2969 | ||
2970 | ignore@^4.0.6: | ||
2971 | version "4.0.6" | ||
2972 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" | ||
2973 | integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== | ||
2974 | |||
2853 | ignore@^5.1.1: | 2975 | ignore@^5.1.1: |
2854 | version "5.1.4" | 2976 | version "5.1.4" |
2855 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" | 2977 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" |
@@ -2862,13 +2984,13 @@ immediate-chunk-store@^2.0.0: | |||
2862 | dependencies: | 2984 | dependencies: |
2863 | queue-microtask "^1.1.2" | 2985 | queue-microtask "^1.1.2" |
2864 | 2986 | ||
2865 | import-fresh@^2.0.0: | 2987 | import-fresh@^3.0.0: |
2866 | version "2.0.0" | 2988 | version "3.2.1" |
2867 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" | 2989 | resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" |
2868 | integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= | 2990 | integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== |
2869 | dependencies: | 2991 | dependencies: |
2870 | caller-path "^2.0.0" | 2992 | parent-module "^1.0.0" |
2871 | resolve-from "^3.0.0" | 2993 | resolve-from "^4.0.0" |
2872 | 2994 | ||
2873 | import-lazy@^2.1.0: | 2995 | import-lazy@^2.1.0: |
2874 | version "2.1.0" | 2996 | version "2.1.0" |
@@ -2880,16 +3002,6 @@ imurmurhash@^0.1.4: | |||
2880 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" | 3002 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" |
2881 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= | 3003 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= |
2882 | 3004 | ||
2883 | indent-string@^3.0.0: | ||
2884 | version "3.2.0" | ||
2885 | resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" | ||
2886 | integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= | ||
2887 | |||
2888 | indent-string@^4.0.0: | ||
2889 | version "4.0.0" | ||
2890 | resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" | ||
2891 | integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== | ||
2892 | |||
2893 | indexof@0.0.1: | 3005 | indexof@0.0.1: |
2894 | version "0.0.1" | 3006 | version "0.0.1" |
2895 | resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" | 3007 | resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" |
@@ -2923,6 +3035,25 @@ ini@^1.3.4, ini@~1.3.0: | |||
2923 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" | 3035 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" |
2924 | integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== | 3036 | integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== |
2925 | 3037 | ||
3038 | inquirer@^7.0.0: | ||
3039 | version "7.0.4" | ||
3040 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703" | ||
3041 | integrity sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ== | ||
3042 | dependencies: | ||
3043 | ansi-escapes "^4.2.1" | ||
3044 | chalk "^2.4.2" | ||
3045 | cli-cursor "^3.1.0" | ||
3046 | cli-width "^2.0.0" | ||
3047 | external-editor "^3.0.3" | ||
3048 | figures "^3.0.0" | ||
3049 | lodash "^4.17.15" | ||
3050 | mute-stream "0.0.8" | ||
3051 | run-async "^2.2.0" | ||
3052 | rxjs "^6.5.3" | ||
3053 | string-width "^4.1.0" | ||
3054 | strip-ansi "^5.1.0" | ||
3055 | through "^2.3.6" | ||
3056 | |||
2926 | ioredis@^4.14.1: | 3057 | ioredis@^4.14.1: |
2927 | version "4.14.1" | 3058 | version "4.14.1" |
2928 | resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.14.1.tgz#b73ded95fcf220f106d33125a92ef6213aa31318" | 3059 | resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.14.1.tgz#b73ded95fcf220f106d33125a92ef6213aa31318" |
@@ -3036,11 +3167,6 @@ is-date-object@^1.0.1: | |||
3036 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" | 3167 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" |
3037 | integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== | 3168 | integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== |
3038 | 3169 | ||
3039 | is-directory@^0.3.1: | ||
3040 | version "0.3.1" | ||
3041 | resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" | ||
3042 | integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= | ||
3043 | |||
3044 | is-extglob@^2.1.1: | 3170 | is-extglob@^2.1.1: |
3045 | version "2.1.1" | 3171 | version "2.1.1" |
3046 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" | 3172 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" |
@@ -3073,7 +3199,7 @@ is-generator@^1.0.2: | |||
3073 | resolved "https://registry.yarnpkg.com/is-generator/-/is-generator-1.0.3.tgz#c14c21057ed36e328db80347966c693f886389f3" | 3199 | resolved "https://registry.yarnpkg.com/is-generator/-/is-generator-1.0.3.tgz#c14c21057ed36e328db80347966c693f886389f3" |
3074 | integrity sha1-wUwhBX7TbjKNuANHlmxpP4hjifM= | 3200 | integrity sha1-wUwhBX7TbjKNuANHlmxpP4hjifM= |
3075 | 3201 | ||
3076 | is-glob@^4.0.1, is-glob@~4.0.1: | 3202 | is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: |
3077 | version "4.0.1" | 3203 | version "4.0.1" |
3078 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" | 3204 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" |
3079 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== | 3205 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== |
@@ -3105,23 +3231,11 @@ is-number@^7.0.0: | |||
3105 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" | 3231 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" |
3106 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== | 3232 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== |
3107 | 3233 | ||
3108 | is-obj@^1.0.0, is-obj@^1.0.1: | 3234 | is-obj@^1.0.0: |
3109 | version "1.0.1" | 3235 | version "1.0.1" |
3110 | resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" | 3236 | resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" |
3111 | integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= | 3237 | integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= |
3112 | 3238 | ||
3113 | is-observable@^1.1.0: | ||
3114 | version "1.1.0" | ||
3115 | resolved "https://registry.yarnpkg.com/is-observable/-/is-observable-1.1.0.tgz#b3e986c8f44de950867cab5403f5a3465005975e" | ||
3116 | integrity sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA== | ||
3117 | dependencies: | ||
3118 | symbol-observable "^1.1.0" | ||
3119 | |||
3120 | is-path-cwd@^2.2.0: | ||
3121 | version "2.2.0" | ||
3122 | resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" | ||
3123 | integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== | ||
3124 | |||
3125 | is-path-inside@^1.0.0: | 3239 | is-path-inside@^1.0.0: |
3126 | version "1.0.1" | 3240 | version "1.0.1" |
3127 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" | 3241 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" |
@@ -3129,11 +3243,6 @@ is-path-inside@^1.0.0: | |||
3129 | dependencies: | 3243 | dependencies: |
3130 | path-is-inside "^1.0.1" | 3244 | path-is-inside "^1.0.1" |
3131 | 3245 | ||
3132 | is-path-inside@^3.0.1: | ||
3133 | version "3.0.2" | ||
3134 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" | ||
3135 | integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== | ||
3136 | |||
3137 | is-promise@^2.1, is-promise@^2.1.0: | 3246 | is-promise@^2.1, is-promise@^2.1.0: |
3138 | version "2.1.0" | 3247 | version "2.1.0" |
3139 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" | 3248 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" |
@@ -3151,11 +3260,6 @@ is-regex@^1.0.5: | |||
3151 | dependencies: | 3260 | dependencies: |
3152 | has "^1.0.3" | 3261 | has "^1.0.3" |
3153 | 3262 | ||
3154 | is-regexp@^1.0.0: | ||
3155 | version "1.0.0" | ||
3156 | resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" | ||
3157 | integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= | ||
3158 | |||
3159 | is-retry-allowed@^1.0.0: | 3263 | is-retry-allowed@^1.0.0: |
3160 | version "1.2.0" | 3264 | version "1.2.0" |
3161 | resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" | 3265 | resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" |
@@ -3171,6 +3275,11 @@ is-stream@^2.0.0: | |||
3171 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" | 3275 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" |
3172 | integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== | 3276 | integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== |
3173 | 3277 | ||
3278 | is-string@^1.0.5: | ||
3279 | version "1.0.5" | ||
3280 | resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" | ||
3281 | integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== | ||
3282 | |||
3174 | is-symbol@^1.0.2: | 3283 | is-symbol@^1.0.2: |
3175 | version "1.0.3" | 3284 | version "1.0.3" |
3176 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" | 3285 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" |
@@ -3198,7 +3307,7 @@ isarray@2.0.1: | |||
3198 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" | 3307 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" |
3199 | integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= | 3308 | integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= |
3200 | 3309 | ||
3201 | isarray@~1.0.0: | 3310 | isarray@^1.0.0, isarray@~1.0.0: |
3202 | version "1.0.0" | 3311 | version "1.0.0" |
3203 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" | 3312 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" |
3204 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= | 3313 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= |
@@ -3208,10 +3317,10 @@ isexe@^2.0.0: | |||
3208 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" | 3317 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" |
3209 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= | 3318 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= |
3210 | 3319 | ||
3211 | iso-639-3@^1.0.1: | 3320 | iso-639-3@^2.0.0: |
3212 | version "1.2.0" | 3321 | version "2.0.0" |
3213 | resolved "https://registry.yarnpkg.com/iso-639-3/-/iso-639-3-1.2.0.tgz#eee1f5e6ca2bbb33e3ecc910857c1c12e8b295be" | 3322 | resolved "https://registry.yarnpkg.com/iso-639-3/-/iso-639-3-2.0.0.tgz#5844c6b885cbeac3571d407de5b5fdcb92f3505f" |
3214 | integrity sha512-jNvD2P4JHNckQH7pc0R0SQ4oPCpyEtgs0nTtjB+DZCUDdygz0cOAxlcnq5KgNjjsqMHbR4Sbgwz2+DflzAZvlQ== | 3323 | integrity sha512-Pp+ctEs/pna6/rj05a5VR3qYxJHBZi95wp20C6Snf/WeghrkR/4G44LPJFqlbyo67XntkcUaxwrGmMeyY+F4mA== |
3215 | 3324 | ||
3216 | isstream@0.1.x, isstream@~0.1.2: | 3325 | isstream@0.1.x, isstream@~0.1.2: |
3217 | version "0.1.2" | 3326 | version "0.1.2" |
@@ -3260,6 +3369,11 @@ json-schema@0.2.3: | |||
3260 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" | 3369 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" |
3261 | integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= | 3370 | integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= |
3262 | 3371 | ||
3372 | json-stable-stringify-without-jsonify@^1.0.1: | ||
3373 | version "1.0.1" | ||
3374 | resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" | ||
3375 | integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= | ||
3376 | |||
3263 | json-stringify-safe@~5.0.1: | 3377 | json-stringify-safe@~5.0.1: |
3264 | version "5.0.1" | 3378 | version "5.0.1" |
3265 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" | 3379 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" |
@@ -3280,9 +3394,9 @@ jsonfile@^4.0.0: | |||
3280 | graceful-fs "^4.1.6" | 3394 | graceful-fs "^4.1.6" |
3281 | 3395 | ||
3282 | jsonld@~2.0.1: | 3396 | jsonld@~2.0.1: |
3283 | version "2.0.1" | 3397 | version "2.0.2" |
3284 | resolved "https://registry.yarnpkg.com/jsonld/-/jsonld-2.0.1.tgz#c08760fb00f429496b45f5c9984bf9be408d3980" | 3398 | resolved "https://registry.yarnpkg.com/jsonld/-/jsonld-2.0.2.tgz#f5d0631de828ce6dee3a14f08cbdc6a53174cd15" |
3285 | integrity sha512-37NIP09U0AnLu94b7ktsgHxZflAqDH8wn2kcLeAjxcL3sbuwJZ1IxIIbWyjSzrKojADWnoZM/btAWlrcGDMgJA== | 3399 | integrity sha512-/TQzRe75/3h2khu57IUojha5oat+M82bm8RYw0jLhlmmPrW/kTWAZ9nGzKPfZWnPYnVVJJMQVc/pU8HCmpv9xg== |
3286 | dependencies: | 3400 | dependencies: |
3287 | canonicalize "^1.0.1" | 3401 | canonicalize "^1.0.1" |
3288 | lru-cache "^5.1.1" | 3402 | lru-cache "^5.1.1" |
@@ -3356,6 +3470,14 @@ latest-version@^3.0.0: | |||
3356 | dependencies: | 3470 | dependencies: |
3357 | package-json "^4.0.0" | 3471 | package-json "^4.0.0" |
3358 | 3472 | ||
3473 | levn@^0.3.0, levn@~0.3.0: | ||
3474 | version "0.3.0" | ||
3475 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" | ||
3476 | integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= | ||
3477 | dependencies: | ||
3478 | prelude-ls "~1.1.2" | ||
3479 | type-check "~0.3.2" | ||
3480 | |||
3359 | libxmljs@0.19.7: | 3481 | libxmljs@0.19.7: |
3360 | version "0.19.7" | 3482 | version "0.19.7" |
3361 | resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.19.7.tgz#96c2151b0b73f33dd29917edec82902587004e5a" | 3483 | resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.19.7.tgz#96c2151b0b73f33dd29917edec82902587004e5a" |
@@ -3365,70 +3487,6 @@ libxmljs@0.19.7: | |||
3365 | nan "~2.14.0" | 3487 | nan "~2.14.0" |
3366 | node-pre-gyp "~0.11.0" | 3488 | node-pre-gyp "~0.11.0" |
3367 | 3489 | ||
3368 | lint-staged@^9.2.0: | ||
3369 | version "9.5.0" | ||
3370 | resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-9.5.0.tgz#290ec605252af646d9b74d73a0fa118362b05a33" | ||
3371 | integrity sha512-nawMob9cb/G1J98nb8v3VC/E8rcX1rryUYXVZ69aT9kde6YWX+uvNOEHY5yf2gcWcTJGiD0kqXmCnS3oD75GIA== | ||
3372 | dependencies: | ||
3373 | chalk "^2.4.2" | ||
3374 | commander "^2.20.0" | ||
3375 | cosmiconfig "^5.2.1" | ||
3376 | debug "^4.1.1" | ||
3377 | dedent "^0.7.0" | ||
3378 | del "^5.0.0" | ||
3379 | execa "^2.0.3" | ||
3380 | listr "^0.14.3" | ||
3381 | log-symbols "^3.0.0" | ||
3382 | micromatch "^4.0.2" | ||
3383 | normalize-path "^3.0.0" | ||
3384 | please-upgrade-node "^3.1.1" | ||
3385 | string-argv "^0.3.0" | ||
3386 | stringify-object "^3.3.0" | ||
3387 | |||
3388 | listr-silent-renderer@^1.1.1: | ||
3389 | version "1.1.1" | ||
3390 | resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" | ||
3391 | integrity sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4= | ||
3392 | |||
3393 | listr-update-renderer@^0.5.0: | ||
3394 | version "0.5.0" | ||
3395 | resolved "https://registry.yarnpkg.com/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz#4ea8368548a7b8aecb7e06d8c95cb45ae2ede6a2" | ||
3396 | integrity sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA== | ||
3397 | dependencies: | ||
3398 | chalk "^1.1.3" | ||
3399 | cli-truncate "^0.2.1" | ||
3400 | elegant-spinner "^1.0.1" | ||
3401 | figures "^1.7.0" | ||
3402 | indent-string "^3.0.0" | ||
3403 | log-symbols "^1.0.2" | ||
3404 | log-update "^2.3.0" | ||
3405 | strip-ansi "^3.0.1" | ||
3406 | |||
3407 | listr-verbose-renderer@^0.5.0: | ||
3408 | version "0.5.0" | ||
3409 | resolved "https://registry.yarnpkg.com/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz#f1132167535ea4c1261102b9f28dac7cba1e03db" | ||
3410 | integrity sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw== | ||
3411 | dependencies: | ||
3412 | chalk "^2.4.1" | ||
3413 | cli-cursor "^2.1.0" | ||
3414 | date-fns "^1.27.2" | ||
3415 | figures "^2.0.0" | ||
3416 | |||
3417 | listr@^0.14.3: | ||
3418 | version "0.14.3" | ||
3419 | resolved "https://registry.yarnpkg.com/listr/-/listr-0.14.3.tgz#2fea909604e434be464c50bddba0d496928fa586" | ||
3420 | integrity sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA== | ||
3421 | dependencies: | ||
3422 | "@samverschueren/stream-to-observable" "^0.3.0" | ||
3423 | is-observable "^1.1.0" | ||
3424 | is-promise "^2.1.0" | ||
3425 | is-stream "^1.1.0" | ||
3426 | listr-silent-renderer "^1.1.1" | ||
3427 | listr-update-renderer "^0.5.0" | ||
3428 | listr-verbose-renderer "^0.5.0" | ||
3429 | p-map "^2.0.0" | ||
3430 | rxjs "^6.3.3" | ||
3431 | |||
3432 | load-ip-set@^2.1.0: | 3490 | load-ip-set@^2.1.0: |
3433 | version "2.1.0" | 3491 | version "2.1.0" |
3434 | resolved "https://registry.yarnpkg.com/load-ip-set/-/load-ip-set-2.1.0.tgz#2d50b737cae41de4e413d213991d4083a3e1784b" | 3492 | resolved "https://registry.yarnpkg.com/load-ip-set/-/load-ip-set-2.1.0.tgz#2d50b737cae41de4e413d213991d4083a3e1784b" |
@@ -3440,6 +3498,24 @@ load-ip-set@^2.1.0: | |||
3440 | simple-get "^3.0.0" | 3498 | simple-get "^3.0.0" |
3441 | split "^1.0.0" | 3499 | split "^1.0.0" |
3442 | 3500 | ||
3501 | load-json-file@^2.0.0: | ||
3502 | version "2.0.0" | ||
3503 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" | ||
3504 | integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= | ||
3505 | dependencies: | ||
3506 | graceful-fs "^4.1.2" | ||
3507 | parse-json "^2.2.0" | ||
3508 | pify "^2.0.0" | ||
3509 | strip-bom "^3.0.0" | ||
3510 | |||
3511 | locate-path@^2.0.0: | ||
3512 | version "2.0.0" | ||
3513 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" | ||
3514 | integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= | ||
3515 | dependencies: | ||
3516 | p-locate "^2.0.0" | ||
3517 | path-exists "^3.0.0" | ||
3518 | |||
3443 | locate-path@^3.0.0: | 3519 | locate-path@^3.0.0: |
3444 | version "3.0.0" | 3520 | version "3.0.0" |
3445 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" | 3521 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" |
@@ -3492,29 +3568,6 @@ log-symbols@2.2.0: | |||
3492 | dependencies: | 3568 | dependencies: |
3493 | chalk "^2.0.1" | 3569 | chalk "^2.0.1" |
3494 | 3570 | ||
3495 | log-symbols@^1.0.2: | ||
3496 | version "1.0.2" | ||
3497 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" | ||
3498 | integrity sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg= | ||
3499 | dependencies: | ||
3500 | chalk "^1.0.0" | ||
3501 | |||
3502 | log-symbols@^3.0.0: | ||
3503 | version "3.0.0" | ||
3504 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" | ||
3505 | integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== | ||
3506 | dependencies: | ||
3507 | chalk "^2.4.2" | ||
3508 | |||
3509 | log-update@^2.3.0: | ||
3510 | version "2.3.0" | ||
3511 | resolved "https://registry.yarnpkg.com/log-update/-/log-update-2.3.0.tgz#88328fd7d1ce7938b29283746f0b1bc126b24708" | ||
3512 | integrity sha1-iDKP19HOeTiykoN0bwsbwSayRwg= | ||
3513 | dependencies: | ||
3514 | ansi-escapes "^3.0.0" | ||
3515 | cli-cursor "^2.0.0" | ||
3516 | wrap-ansi "^3.0.1" | ||
3517 | |||
3518 | logform@^2.1.1: | 3571 | logform@^2.1.1: |
3519 | version "2.1.2" | 3572 | version "2.1.2" |
3520 | resolved "https://registry.yarnpkg.com/logform/-/logform-2.1.2.tgz#957155ebeb67a13164069825ce67ddb5bb2dd360" | 3573 | resolved "https://registry.yarnpkg.com/logform/-/logform-2.1.2.tgz#957155ebeb67a13164069825ce67ddb5bb2dd360" |
@@ -3669,24 +3722,11 @@ merge-stream@^2.0.0: | |||
3669 | resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" | 3722 | resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" |
3670 | integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== | 3723 | integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== |
3671 | 3724 | ||
3672 | merge2@^1.2.3, merge2@^1.3.0: | ||
3673 | version "1.3.0" | ||
3674 | resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" | ||
3675 | integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== | ||
3676 | |||
3677 | methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: | 3725 | methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: |
3678 | version "1.1.2" | 3726 | version "1.1.2" |
3679 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" | 3727 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" |
3680 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= | 3728 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= |
3681 | 3729 | ||
3682 | micromatch@^4.0.2: | ||
3683 | version "4.0.2" | ||
3684 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" | ||
3685 | integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== | ||
3686 | dependencies: | ||
3687 | braces "^3.0.1" | ||
3688 | picomatch "^2.0.5" | ||
3689 | |||
3690 | mime-db@1.43.0: | 3730 | mime-db@1.43.0: |
3691 | version "1.43.0" | 3731 | version "1.43.0" |
3692 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" | 3732 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" |
@@ -3709,11 +3749,6 @@ mime@^2.4.0: | |||
3709 | resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" | 3749 | resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" |
3710 | integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== | 3750 | integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== |
3711 | 3751 | ||
3712 | mimic-fn@^1.0.0: | ||
3713 | version "1.2.0" | ||
3714 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" | ||
3715 | integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== | ||
3716 | |||
3717 | mimic-fn@^2.1.0: | 3752 | mimic-fn@^2.1.0: |
3718 | version "2.1.0" | 3753 | version "2.1.0" |
3719 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" | 3754 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" |
@@ -3789,9 +3824,9 @@ mocha-parallel-tests@^2.2.1: | |||
3789 | yargs "^13.2.4" | 3824 | yargs "^13.2.4" |
3790 | 3825 | ||
3791 | mocha@^7.0.0: | 3826 | mocha@^7.0.0: |
3792 | version "7.0.0" | 3827 | version "7.0.1" |
3793 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.0.0.tgz#c60d14bf3de9601f549b3ff5be657eb8381c54bf" | 3828 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-7.0.1.tgz#276186d35a4852f6249808c6dd4a1376cbf6c6ce" |
3794 | integrity sha512-CirsOPbO3jU86YKjjMzFLcXIb5YiGLUrjrXFHoJ3e2z9vWiaZVCZQ2+gtRGMPWF+nFhN6AWwLM/juzAQ6KRkbA== | 3829 | integrity sha512-9eWmWTdHLXh72rGrdZjNbG3aa1/3NRPpul1z0D979QpEnFdCG0Q5tv834N+94QEN2cysfV72YocQ3fn87s70fg== |
3795 | dependencies: | 3830 | dependencies: |
3796 | ansi-colors "3.2.3" | 3831 | ansi-colors "3.2.3" |
3797 | browser-stdout "1.3.1" | 3832 | browser-stdout "1.3.1" |
@@ -3893,7 +3928,7 @@ multistream@^4.0.0: | |||
3893 | dependencies: | 3928 | dependencies: |
3894 | readable-stream "^3.4.0" | 3929 | readable-stream "^3.4.0" |
3895 | 3930 | ||
3896 | mute-stream@~0.0.4: | 3931 | mute-stream@0.0.8, mute-stream@~0.0.4: |
3897 | version "0.0.8" | 3932 | version "0.0.8" |
3898 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" | 3933 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" |
3899 | integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== | 3934 | integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== |
@@ -3908,6 +3943,11 @@ napi-build-utils@^1.0.1: | |||
3908 | resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508" | 3943 | resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508" |
3909 | integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA== | 3944 | integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA== |
3910 | 3945 | ||
3946 | natural-compare@^1.4.0: | ||
3947 | version "1.4.0" | ||
3948 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" | ||
3949 | integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= | ||
3950 | |||
3911 | ncp@1.0.x: | 3951 | ncp@1.0.x: |
3912 | version "1.0.1" | 3952 | version "1.0.1" |
3913 | resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246" | 3953 | resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246" |
@@ -3942,6 +3982,11 @@ next-tick@1, next-tick@~1.0.0: | |||
3942 | resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" | 3982 | resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" |
3943 | integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= | 3983 | integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= |
3944 | 3984 | ||
3985 | nice-try@^1.0.4: | ||
3986 | version "1.0.5" | ||
3987 | resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" | ||
3988 | integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== | ||
3989 | |||
3945 | nocache@2.1.0: | 3990 | nocache@2.1.0: |
3946 | version "2.1.0" | 3991 | version "2.1.0" |
3947 | resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" | 3992 | resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" |
@@ -3962,10 +4007,10 @@ node-environment-flags@1.0.6: | |||
3962 | object.getownpropertydescriptors "^2.0.3" | 4007 | object.getownpropertydescriptors "^2.0.3" |
3963 | semver "^5.7.0" | 4008 | semver "^5.7.0" |
3964 | 4009 | ||
3965 | node-forge@^0.8.1: | 4010 | node-forge@^0.9.1: |
3966 | version "0.8.5" | 4011 | version "0.9.1" |
3967 | resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.8.5.tgz#57906f07614dc72762c84cef442f427c0e1b86ee" | 4012 | resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.1.tgz#775368e6846558ab6676858a4d8c6e8d16c677b5" |
3968 | integrity sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q== | 4013 | integrity sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ== |
3969 | 4014 | ||
3970 | node-gyp-build@~3.7.0: | 4015 | node-gyp-build@~3.7.0: |
3971 | version "3.7.0" | 4016 | version "3.7.0" |
@@ -4083,12 +4128,13 @@ npm-normalize-package-bin@^1.0.1: | |||
4083 | integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== | 4128 | integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== |
4084 | 4129 | ||
4085 | npm-packlist@^1.1.6: | 4130 | npm-packlist@^1.1.6: |
4086 | version "1.4.7" | 4131 | version "1.4.8" |
4087 | resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.7.tgz#9e954365a06b80b18111ea900945af4f88ed4848" | 4132 | resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" |
4088 | integrity sha512-vAj7dIkp5NhieaGZxBJB8fF4R0078rqsmhJcAfXZ6O7JJhjhPK96n5Ry1oZcfLXgfun0GWTZPOxaEyqv8GBykQ== | 4133 | integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== |
4089 | dependencies: | 4134 | dependencies: |
4090 | ignore-walk "^3.0.1" | 4135 | ignore-walk "^3.0.1" |
4091 | npm-bundled "^1.0.1" | 4136 | npm-bundled "^1.0.1" |
4137 | npm-normalize-package-bin "^1.0.1" | ||
4092 | 4138 | ||
4093 | npm-run-path@^2.0.0: | 4139 | npm-run-path@^2.0.0: |
4094 | version "2.0.2" | 4140 | version "2.0.2" |
@@ -4097,13 +4143,6 @@ npm-run-path@^2.0.0: | |||
4097 | dependencies: | 4143 | dependencies: |
4098 | path-key "^2.0.0" | 4144 | path-key "^2.0.0" |
4099 | 4145 | ||
4100 | npm-run-path@^3.0.0: | ||
4101 | version "3.1.0" | ||
4102 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" | ||
4103 | integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== | ||
4104 | dependencies: | ||
4105 | path-key "^3.0.0" | ||
4106 | |||
4107 | npm-run-path@^4.0.0: | 4146 | npm-run-path@^4.0.0: |
4108 | version "4.0.1" | 4147 | version "4.0.1" |
4109 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" | 4148 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" |
@@ -4173,7 +4212,7 @@ object.assign@4.1.0, object.assign@^4.1.0: | |||
4173 | has-symbols "^1.0.0" | 4212 | has-symbols "^1.0.0" |
4174 | object-keys "^1.0.11" | 4213 | object-keys "^1.0.11" |
4175 | 4214 | ||
4176 | object.getownpropertydescriptors@^2.0.3: | 4215 | object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: |
4177 | version "2.1.0" | 4216 | version "2.1.0" |
4178 | resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" | 4217 | resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" |
4179 | integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== | 4218 | integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== |
@@ -4181,6 +4220,16 @@ object.getownpropertydescriptors@^2.0.3: | |||
4181 | define-properties "^1.1.3" | 4220 | define-properties "^1.1.3" |
4182 | es-abstract "^1.17.0-next.1" | 4221 | es-abstract "^1.17.0-next.1" |
4183 | 4222 | ||
4223 | object.values@^1.1.0: | ||
4224 | version "1.1.1" | ||
4225 | resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" | ||
4226 | integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== | ||
4227 | dependencies: | ||
4228 | define-properties "^1.1.3" | ||
4229 | es-abstract "^1.17.0-next.1" | ||
4230 | function-bind "^1.1.1" | ||
4231 | has "^1.0.3" | ||
4232 | |||
4184 | on-finished@^2.3.0, on-finished@~2.3.0: | 4233 | on-finished@^2.3.0, on-finished@~2.3.0: |
4185 | version "2.3.0" | 4234 | version "2.3.0" |
4186 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" | 4235 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" |
@@ -4205,13 +4254,6 @@ one-time@0.0.4: | |||
4205 | resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e" | 4254 | resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e" |
4206 | integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4= | 4255 | integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4= |
4207 | 4256 | ||
4208 | onetime@^2.0.0: | ||
4209 | version "2.0.1" | ||
4210 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" | ||
4211 | integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= | ||
4212 | dependencies: | ||
4213 | mimic-fn "^1.0.0" | ||
4214 | |||
4215 | onetime@^5.1.0: | 4257 | onetime@^5.1.0: |
4216 | version "5.1.0" | 4258 | version "5.1.0" |
4217 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" | 4259 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" |
@@ -4241,6 +4283,18 @@ opn@^6.0.0: | |||
4241 | dependencies: | 4283 | dependencies: |
4242 | is-wsl "^1.1.0" | 4284 | is-wsl "^1.1.0" |
4243 | 4285 | ||
4286 | optionator@^0.8.3: | ||
4287 | version "0.8.3" | ||
4288 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" | ||
4289 | integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== | ||
4290 | dependencies: | ||
4291 | deep-is "~0.1.3" | ||
4292 | fast-levenshtein "~2.0.6" | ||
4293 | levn "~0.3.0" | ||
4294 | prelude-ls "~1.1.2" | ||
4295 | type-check "~0.3.2" | ||
4296 | word-wrap "~1.2.3" | ||
4297 | |||
4244 | os-homedir@^1.0.0: | 4298 | os-homedir@^1.0.0: |
4245 | version "1.0.2" | 4299 | version "1.0.2" |
4246 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" | 4300 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" |
@@ -4269,6 +4323,13 @@ p-finally@^2.0.0: | |||
4269 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" | 4323 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" |
4270 | integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== | 4324 | integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== |
4271 | 4325 | ||
4326 | p-limit@^1.1.0: | ||
4327 | version "1.3.0" | ||
4328 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" | ||
4329 | integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== | ||
4330 | dependencies: | ||
4331 | p-try "^1.0.0" | ||
4332 | |||
4272 | p-limit@^2.0.0, p-limit@^2.2.0: | 4333 | p-limit@^2.0.0, p-limit@^2.2.0: |
4273 | version "2.2.2" | 4334 | version "2.2.2" |
4274 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" | 4335 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" |
@@ -4276,6 +4337,13 @@ p-limit@^2.0.0, p-limit@^2.2.0: | |||
4276 | dependencies: | 4337 | dependencies: |
4277 | p-try "^2.0.0" | 4338 | p-try "^2.0.0" |
4278 | 4339 | ||
4340 | p-locate@^2.0.0: | ||
4341 | version "2.0.0" | ||
4342 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" | ||
4343 | integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= | ||
4344 | dependencies: | ||
4345 | p-limit "^1.1.0" | ||
4346 | |||
4279 | p-locate@^3.0.0: | 4347 | p-locate@^3.0.0: |
4280 | version "3.0.0" | 4348 | version "3.0.0" |
4281 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" | 4349 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" |
@@ -4290,18 +4358,6 @@ p-locate@^4.1.0: | |||
4290 | dependencies: | 4358 | dependencies: |
4291 | p-limit "^2.2.0" | 4359 | p-limit "^2.2.0" |
4292 | 4360 | ||
4293 | p-map@^2.0.0: | ||
4294 | version "2.1.0" | ||
4295 | resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" | ||
4296 | integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== | ||
4297 | |||
4298 | p-map@^3.0.0: | ||
4299 | version "3.0.0" | ||
4300 | resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" | ||
4301 | integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== | ||
4302 | dependencies: | ||
4303 | aggregate-error "^3.0.0" | ||
4304 | |||
4305 | p-timeout@^3.1.0: | 4361 | p-timeout@^3.1.0: |
4306 | version "3.2.0" | 4362 | version "3.2.0" |
4307 | resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" | 4363 | resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" |
@@ -4309,6 +4365,11 @@ p-timeout@^3.1.0: | |||
4309 | dependencies: | 4365 | dependencies: |
4310 | p-finally "^1.0.0" | 4366 | p-finally "^1.0.0" |
4311 | 4367 | ||
4368 | p-try@^1.0.0: | ||
4369 | version "1.0.0" | ||
4370 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" | ||
4371 | integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= | ||
4372 | |||
4312 | p-try@^2.0.0: | 4373 | p-try@^2.0.0: |
4313 | version "2.2.0" | 4374 | version "2.2.0" |
4314 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" | 4375 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" |
@@ -4336,6 +4397,20 @@ packet-reader@1.0.0: | |||
4336 | resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" | 4397 | resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" |
4337 | integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== | 4398 | integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== |
4338 | 4399 | ||
4400 | parent-module@^1.0.0: | ||
4401 | version "1.0.1" | ||
4402 | resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" | ||
4403 | integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== | ||
4404 | dependencies: | ||
4405 | callsites "^3.0.0" | ||
4406 | |||
4407 | parse-json@^2.2.0: | ||
4408 | version "2.2.0" | ||
4409 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" | ||
4410 | integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= | ||
4411 | dependencies: | ||
4412 | error-ex "^1.2.0" | ||
4413 | |||
4339 | parse-json@^4.0.0: | 4414 | parse-json@^4.0.0: |
4340 | version "4.0.0" | 4415 | version "4.0.0" |
4341 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" | 4416 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" |
@@ -4408,7 +4483,7 @@ path-is-inside@^1.0.1: | |||
4408 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" | 4483 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" |
4409 | integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= | 4484 | integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= |
4410 | 4485 | ||
4411 | path-key@^2.0.0: | 4486 | path-key@^2.0.0, path-key@^2.0.1: |
4412 | version "2.0.1" | 4487 | version "2.0.1" |
4413 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" | 4488 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" |
4414 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= | 4489 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= |
@@ -4428,10 +4503,12 @@ path-to-regexp@0.1.7: | |||
4428 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" | 4503 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" |
4429 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= | 4504 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= |
4430 | 4505 | ||
4431 | path-type@^4.0.0: | 4506 | path-type@^2.0.0: |
4432 | version "4.0.0" | 4507 | version "2.0.0" |
4433 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" | 4508 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" |
4434 | integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== | 4509 | integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= |
4510 | dependencies: | ||
4511 | pify "^2.0.0" | ||
4435 | 4512 | ||
4436 | pathval@^1.1.0: | 4513 | pathval@^1.1.0: |
4437 | version "1.1.0" | 4514 | version "1.1.0" |
@@ -4448,14 +4525,14 @@ peek-stream@^1.1.1: | |||
4448 | through2 "^2.0.3" | 4525 | through2 "^2.0.3" |
4449 | 4526 | ||
4450 | pem@^1.12.3: | 4527 | pem@^1.12.3: |
4451 | version "1.14.3" | 4528 | version "1.14.4" |
4452 | resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.3.tgz#347e5a5c194a5f7612b88083e45042fcc4fb4901" | 4529 | resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.4.tgz#a68c70c6e751ccc5b3b5bcd7af78b0aec1177ff9" |
4453 | integrity sha512-Q+AMVMD3fzeVvZs5PHeI+pVt0hgZY2fjhkliBW43qyONLgCXPVk1ryim43F9eupHlNGLJNT5T/NNrzhUdiC5Zg== | 4530 | integrity sha512-v8lH3NpirgiEmbOqhx0vwQTxwi0ExsiWBGYh0jYNq7K6mQuO4gI6UEFlr6fLAdv9TPXRt6GqiwE37puQdIDS8g== |
4454 | dependencies: | 4531 | dependencies: |
4455 | es6-promisify "^6.0.0" | 4532 | es6-promisify "^6.0.0" |
4456 | md5 "^2.2.1" | 4533 | md5 "^2.2.1" |
4457 | os-tmpdir "^1.0.1" | 4534 | os-tmpdir "^1.0.1" |
4458 | which "^1.3.1" | 4535 | which "^2.0.2" |
4459 | 4536 | ||
4460 | performance-now@^2.1.0: | 4537 | performance-now@^2.1.0: |
4461 | version "2.1.0" | 4538 | version "2.1.0" |
@@ -4485,10 +4562,10 @@ pg-packet-stream@^1.1.0: | |||
4485 | resolved "https://registry.yarnpkg.com/pg-packet-stream/-/pg-packet-stream-1.1.0.tgz#e45c3ae678b901a2873af1e17b92d787962ef914" | 4562 | resolved "https://registry.yarnpkg.com/pg-packet-stream/-/pg-packet-stream-1.1.0.tgz#e45c3ae678b901a2873af1e17b92d787962ef914" |
4486 | integrity sha512-kRBH0tDIW/8lfnnOyTwKD23ygJ/kexQVXZs7gEyBljw4FYqimZFxnMMx50ndZ8In77QgfGuItS5LLclC2TtjYg== | 4563 | integrity sha512-kRBH0tDIW/8lfnnOyTwKD23ygJ/kexQVXZs7gEyBljw4FYqimZFxnMMx50ndZ8In77QgfGuItS5LLclC2TtjYg== |
4487 | 4564 | ||
4488 | pg-pool@^2.0.9: | 4565 | pg-pool@^2.0.10: |
4489 | version "2.0.9" | 4566 | version "2.0.10" |
4490 | resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-2.0.9.tgz#7ed69a27e204f99e9804a851404db6aa908a6dea" | 4567 | resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-2.0.10.tgz#842ee23b04e86824ce9d786430f8365082d81c4a" |
4491 | integrity sha512-gNiuIEKNCT3OnudQM2kvgSnXsLkSpd6mS/fRnqs6ANtrke6j8OY5l9mnAryf1kgwJMWLg0C1N1cYTZG1xmEYHQ== | 4568 | integrity sha512-qdwzY92bHf3nwzIUcj+zJ0Qo5lpG/YxchahxIN8+ZVmXqkahKXsnl2aiJPHLYN9o5mB/leG+Xh6XKxtP7e0sjg== |
4492 | 4569 | ||
4493 | pg-types@^2.1.0: | 4570 | pg-types@^2.1.0: |
4494 | version "2.2.0" | 4571 | version "2.2.0" |
@@ -4502,15 +4579,15 @@ pg-types@^2.1.0: | |||
4502 | postgres-interval "^1.1.0" | 4579 | postgres-interval "^1.1.0" |
4503 | 4580 | ||
4504 | pg@^7.4.1: | 4581 | pg@^7.4.1: |
4505 | version "7.17.0" | 4582 | version "7.18.1" |
4506 | resolved "https://registry.yarnpkg.com/pg/-/pg-7.17.0.tgz#1fcf82238dcbebea63e192c944345c25c86992fc" | 4583 | resolved "https://registry.yarnpkg.com/pg/-/pg-7.18.1.tgz#67f59c47a99456fcb34f9fe53662b79d4a992f6d" |
4507 | integrity sha512-70Q4ZzIdPgwMPb3zUIzAUwigNJ4v5vsWdMED6OzXMfOECeYTvTm7iSC3FpKizu/R1BHL8Do3bLs6ltGfOTAnqg== | 4584 | integrity sha512-1KtKBKg/zWrjEEv//klBbVOPGucuc7HHeJf6OEMueVcUeyF3yueHf+DvhVwBjIAe9/97RAydO/lWjkcMwssuEw== |
4508 | dependencies: | 4585 | dependencies: |
4509 | buffer-writer "2.0.0" | 4586 | buffer-writer "2.0.0" |
4510 | packet-reader "1.0.0" | 4587 | packet-reader "1.0.0" |
4511 | pg-connection-string "0.1.3" | 4588 | pg-connection-string "0.1.3" |
4512 | pg-packet-stream "^1.1.0" | 4589 | pg-packet-stream "^1.1.0" |
4513 | pg-pool "^2.0.9" | 4590 | pg-pool "^2.0.10" |
4514 | pg-types "^2.1.0" | 4591 | pg-types "^2.1.0" |
4515 | pgpass "1.x" | 4592 | pgpass "1.x" |
4516 | semver "4.3.2" | 4593 | semver "4.3.2" |
@@ -4522,7 +4599,7 @@ pgpass@1.x: | |||
4522 | dependencies: | 4599 | dependencies: |
4523 | split "^1.0.0" | 4600 | split "^1.0.0" |
4524 | 4601 | ||
4525 | picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.0.7: | 4602 | picomatch@^2.0.4, picomatch@^2.0.7: |
4526 | version "2.2.1" | 4603 | version "2.2.1" |
4527 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" | 4604 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" |
4528 | integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== | 4605 | integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== |
@@ -4532,11 +4609,23 @@ piece-length@^2.0.1: | |||
4532 | resolved "https://registry.yarnpkg.com/piece-length/-/piece-length-2.0.1.tgz#dbed4e78976955f34466d0a65304d0cb21914ac9" | 4609 | resolved "https://registry.yarnpkg.com/piece-length/-/piece-length-2.0.1.tgz#dbed4e78976955f34466d0a65304d0cb21914ac9" |
4533 | integrity sha512-dBILiDmm43y0JPISWEmVGKBETQjwJe6mSU9GND+P9KW0SJGUwoU/odyH1nbalOP9i8WSYuqf1lQnaj92Bhw+Ug== | 4610 | integrity sha512-dBILiDmm43y0JPISWEmVGKBETQjwJe6mSU9GND+P9KW0SJGUwoU/odyH1nbalOP9i8WSYuqf1lQnaj92Bhw+Ug== |
4534 | 4611 | ||
4612 | pify@^2.0.0: | ||
4613 | version "2.3.0" | ||
4614 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" | ||
4615 | integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= | ||
4616 | |||
4535 | pify@^3.0.0: | 4617 | pify@^3.0.0: |
4536 | version "3.0.0" | 4618 | version "3.0.0" |
4537 | resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" | 4619 | resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" |
4538 | integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= | 4620 | integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= |
4539 | 4621 | ||
4622 | pkg-dir@^2.0.0: | ||
4623 | version "2.0.0" | ||
4624 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" | ||
4625 | integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= | ||
4626 | dependencies: | ||
4627 | find-up "^2.1.0" | ||
4628 | |||
4540 | pkginfo@0.3.x: | 4629 | pkginfo@0.3.x: |
4541 | version "0.3.1" | 4630 | version "0.3.1" |
4542 | resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" | 4631 | resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" |
@@ -4547,13 +4636,6 @@ pkginfo@0.x.x: | |||
4547 | resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff" | 4636 | resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff" |
4548 | integrity sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8= | 4637 | integrity sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8= |
4549 | 4638 | ||
4550 | please-upgrade-node@^3.1.1: | ||
4551 | version "3.2.0" | ||
4552 | resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" | ||
4553 | integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== | ||
4554 | dependencies: | ||
4555 | semver-compare "^1.0.0" | ||
4556 | |||
4557 | postgres-array@~2.0.0: | 4639 | postgres-array@~2.0.0: |
4558 | version "2.0.0" | 4640 | version "2.0.0" |
4559 | resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" | 4641 | resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" |
@@ -4597,6 +4679,11 @@ prebuild-install@^5.3.3: | |||
4597 | tunnel-agent "^0.6.0" | 4679 | tunnel-agent "^0.6.0" |
4598 | which-pm-runs "^1.0.0" | 4680 | which-pm-runs "^1.0.0" |
4599 | 4681 | ||
4682 | prelude-ls@~1.1.2: | ||
4683 | version "1.1.2" | ||
4684 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" | ||
4685 | integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= | ||
4686 | |||
4600 | prepend-http@^1.0.1: | 4687 | prepend-http@^1.0.1: |
4601 | version "1.0.4" | 4688 | version "1.0.4" |
4602 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" | 4689 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" |
@@ -4607,6 +4694,11 @@ process-nextick-args@~2.0.0: | |||
4607 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" | 4694 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" |
4608 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== | 4695 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== |
4609 | 4696 | ||
4697 | progress@^2.0.0: | ||
4698 | version "2.0.3" | ||
4699 | resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" | ||
4700 | integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== | ||
4701 | |||
4610 | promise.prototype.finally@^3.1.1: | 4702 | promise.prototype.finally@^3.1.1: |
4611 | version "3.1.2" | 4703 | version "3.1.2" |
4612 | resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz#b8af89160c9c673cefe3b4c4435b53cfd0287067" | 4704 | resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz#b8af89160c9c673cefe3b4c4435b53cfd0287067" |
@@ -4775,12 +4867,29 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: | |||
4775 | strip-json-comments "~2.0.1" | 4867 | strip-json-comments "~2.0.1" |
4776 | 4868 | ||
4777 | rdf-canonize@^1.0.2: | 4869 | rdf-canonize@^1.0.2: |
4778 | version "1.0.3" | 4870 | version "1.1.0" |
4779 | resolved "https://registry.yarnpkg.com/rdf-canonize/-/rdf-canonize-1.0.3.tgz#71dc56bb808a39d12e3ca17674c15f881cad648a" | 4871 | resolved "https://registry.yarnpkg.com/rdf-canonize/-/rdf-canonize-1.1.0.tgz#61d1609bbdb3234b8f38c9c34ad889bf670e089d" |
4780 | integrity sha512-piLMOB5Q6LJSVx2XzmdpHktYVb8TmVTy8coXJBFtdkcMC96DknZOuzpAYqCWx2ERZX7xEW+mMi8/wDuMJS/95w== | 4872 | integrity sha512-DV06OnhVfl2zcZJQCt+YvU+hoZVgpyQpNFLeAmghq8RJybUxD3B4LRzlBquYS5k+LLd8/c3g5Gnhkqjw5qRMvg== |
4873 | dependencies: | ||
4874 | node-forge "^0.9.1" | ||
4875 | semver "^6.3.0" | ||
4876 | |||
4877 | read-pkg-up@^2.0.0: | ||
4878 | version "2.0.0" | ||
4879 | resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" | ||
4880 | integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= | ||
4881 | dependencies: | ||
4882 | find-up "^2.0.0" | ||
4883 | read-pkg "^2.0.0" | ||
4884 | |||
4885 | read-pkg@^2.0.0: | ||
4886 | version "2.0.0" | ||
4887 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" | ||
4888 | integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= | ||
4781 | dependencies: | 4889 | dependencies: |
4782 | node-forge "^0.8.1" | 4890 | load-json-file "^2.0.0" |
4783 | semver "^5.6.0" | 4891 | normalize-package-data "^2.3.2" |
4892 | path-type "^2.0.0" | ||
4784 | 4893 | ||
4785 | read-pkg@^4.0.1: | 4894 | read-pkg@^4.0.1: |
4786 | version "4.0.1" | 4895 | version "4.0.1" |
@@ -4832,9 +4941,9 @@ readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.2.2, readable | |||
4832 | util-deprecate "~1.0.1" | 4941 | util-deprecate "~1.0.1" |
4833 | 4942 | ||
4834 | readable-stream@^3.0.0, readable-stream@^3.0.1, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0: | 4943 | readable-stream@^3.0.0, readable-stream@^3.0.1, readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0: |
4835 | version "3.4.0" | 4944 | version "3.5.0" |
4836 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" | 4945 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.5.0.tgz#465d70e6d1087f6162d079cd0b5db7fbebfd1606" |
4837 | integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== | 4946 | integrity sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA== |
4838 | dependencies: | 4947 | dependencies: |
4839 | inherits "^2.0.3" | 4948 | inherits "^2.0.3" |
4840 | string_decoder "^1.1.1" | 4949 | string_decoder "^1.1.1" |
@@ -4907,6 +5016,16 @@ reflect-metadata@^0.1.12: | |||
4907 | resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" | 5016 | resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" |
4908 | integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== | 5017 | integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== |
4909 | 5018 | ||
5019 | regexpp@^2.0.1: | ||
5020 | version "2.0.1" | ||
5021 | resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" | ||
5022 | integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== | ||
5023 | |||
5024 | regexpp@^3.0.0: | ||
5025 | version "3.0.0" | ||
5026 | resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e" | ||
5027 | integrity sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g== | ||
5028 | |||
4910 | registry-auth-token@^3.0.1: | 5029 | registry-auth-token@^3.0.1: |
4911 | version "3.4.0" | 5030 | version "3.4.0" |
4912 | resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" | 5031 | resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" |
@@ -4974,10 +5093,10 @@ resolve-from@^2.0.0: | |||
4974 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" | 5093 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" |
4975 | integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= | 5094 | integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= |
4976 | 5095 | ||
4977 | resolve-from@^3.0.0: | 5096 | resolve-from@^4.0.0: |
4978 | version "3.0.0" | 5097 | version "4.0.0" |
4979 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" | 5098 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" |
4980 | integrity sha1-six699nWiBvItuZTM17rywoYh0g= | 5099 | integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== |
4981 | 5100 | ||
4982 | resolve-pkg@^1.0.0: | 5101 | resolve-pkg@^1.0.0: |
4983 | version "1.0.0" | 5102 | version "1.0.0" |
@@ -4986,19 +5105,19 @@ resolve-pkg@^1.0.0: | |||
4986 | dependencies: | 5105 | dependencies: |
4987 | resolve-from "^2.0.0" | 5106 | resolve-from "^2.0.0" |
4988 | 5107 | ||
4989 | resolve@^1.10.0, resolve@^1.3.2: | 5108 | resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1: |
4990 | version "1.14.2" | 5109 | version "1.15.0" |
4991 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.2.tgz#dbf31d0fa98b1f29aa5169783b9c290cb865fea2" | 5110 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5" |
4992 | integrity sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ== | 5111 | integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw== |
4993 | dependencies: | 5112 | dependencies: |
4994 | path-parse "^1.0.6" | 5113 | path-parse "^1.0.6" |
4995 | 5114 | ||
4996 | restore-cursor@^2.0.0: | 5115 | restore-cursor@^3.1.0: |
4997 | version "2.0.0" | 5116 | version "3.1.0" |
4998 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" | 5117 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" |
4999 | integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= | 5118 | integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== |
5000 | dependencies: | 5119 | dependencies: |
5001 | onetime "^2.0.0" | 5120 | onetime "^5.1.0" |
5002 | signal-exit "^3.0.2" | 5121 | signal-exit "^3.0.2" |
5003 | 5122 | ||
5004 | retry-as-promised@^3.2.0: | 5123 | retry-as-promised@^3.2.0: |
@@ -5008,16 +5127,18 @@ retry-as-promised@^3.2.0: | |||
5008 | dependencies: | 5127 | dependencies: |
5009 | any-promise "^1.3.0" | 5128 | any-promise "^1.3.0" |
5010 | 5129 | ||
5011 | reusify@^1.0.0: | ||
5012 | version "1.0.4" | ||
5013 | resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" | ||
5014 | integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== | ||
5015 | |||
5016 | revalidator@0.1.x: | 5130 | revalidator@0.1.x: |
5017 | version "0.1.8" | 5131 | version "0.1.8" |
5018 | resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" | 5132 | resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" |
5019 | integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs= | 5133 | integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs= |
5020 | 5134 | ||
5135 | rimraf@2.6.3: | ||
5136 | version "2.6.3" | ||
5137 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" | ||
5138 | integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== | ||
5139 | dependencies: | ||
5140 | glob "^7.1.3" | ||
5141 | |||
5021 | rimraf@2.x.x, rimraf@^2.6.1, rimraf@^2.6.3: | 5142 | rimraf@2.x.x, rimraf@^2.6.1, rimraf@^2.6.3: |
5022 | version "2.7.1" | 5143 | version "2.7.1" |
5023 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" | 5144 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" |
@@ -5026,18 +5147,25 @@ rimraf@2.x.x, rimraf@^2.6.1, rimraf@^2.6.3: | |||
5026 | glob "^7.1.3" | 5147 | glob "^7.1.3" |
5027 | 5148 | ||
5028 | rimraf@^3.0.0: | 5149 | rimraf@^3.0.0: |
5029 | version "3.0.0" | 5150 | version "3.0.1" |
5030 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b" | 5151 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.1.tgz#48d3d4cb46c80d388ab26cd61b1b466ae9ae225a" |
5031 | integrity sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg== | 5152 | integrity sha512-IQ4ikL8SjBiEDZfk+DFVwqRK8md24RWMEJkdSlgNLkyyAImcjf8SWvU1qFMDOb4igBClbTQ/ugPqXcRwdFTxZw== |
5032 | dependencies: | 5153 | dependencies: |
5033 | glob "^7.1.3" | 5154 | glob "^7.1.3" |
5034 | 5155 | ||
5156 | run-async@^2.2.0: | ||
5157 | version "2.3.0" | ||
5158 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" | ||
5159 | integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= | ||
5160 | dependencies: | ||
5161 | is-promise "^2.1.0" | ||
5162 | |||
5035 | run-parallel-limit@^1.0.3: | 5163 | run-parallel-limit@^1.0.3: |
5036 | version "1.0.5" | 5164 | version "1.0.5" |
5037 | resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.0.5.tgz#c29a4fd17b4df358cb52a8a697811a63c984f1b7" | 5165 | resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.0.5.tgz#c29a4fd17b4df358cb52a8a697811a63c984f1b7" |
5038 | integrity sha512-NsY+oDngvrvMxKB3G8ijBzIema6aYbQMD2bHOamvN52BysbIGTnEY2xsNyfrcr9GhY995/t/0nQN3R3oZvaDlg== | 5166 | integrity sha512-NsY+oDngvrvMxKB3G8ijBzIema6aYbQMD2bHOamvN52BysbIGTnEY2xsNyfrcr9GhY995/t/0nQN3R3oZvaDlg== |
5039 | 5167 | ||
5040 | run-parallel@^1.0.0, run-parallel@^1.1.2, run-parallel@^1.1.6, run-parallel@^1.1.9: | 5168 | run-parallel@^1.0.0, run-parallel@^1.1.2, run-parallel@^1.1.6: |
5041 | version "1.1.9" | 5169 | version "1.1.9" |
5042 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" | 5170 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" |
5043 | integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== | 5171 | integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== |
@@ -5052,7 +5180,7 @@ rusha@^0.8.1: | |||
5052 | resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.13.tgz#9a084e7b860b17bff3015b92c67a6a336191513a" | 5180 | resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.13.tgz#9a084e7b860b17bff3015b92c67a6a336191513a" |
5053 | integrity sha1-mghOe4YLF7/zAVuSxnpqM2GRUTo= | 5181 | integrity sha1-mghOe4YLF7/zAVuSxnpqM2GRUTo= |
5054 | 5182 | ||
5055 | rxjs@^6.3.3, rxjs@^6.5.2: | 5183 | rxjs@^6.5.2, rxjs@^6.5.3: |
5056 | version "6.5.4" | 5184 | version "6.5.4" |
5057 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" | 5185 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" |
5058 | integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== | 5186 | integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== |
@@ -5089,11 +5217,6 @@ scripty@^1.5.0: | |||
5089 | lodash "^4.17.11" | 5217 | lodash "^4.17.11" |
5090 | resolve-pkg "^1.0.0" | 5218 | resolve-pkg "^1.0.0" |
5091 | 5219 | ||
5092 | semver-compare@^1.0.0: | ||
5093 | version "1.0.0" | ||
5094 | resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" | ||
5095 | integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= | ||
5096 | |||
5097 | semver-diff@^2.0.0: | 5220 | semver-diff@^2.0.0: |
5098 | version "2.1.0" | 5221 | version "2.1.0" |
5099 | resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" | 5222 | resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" |
@@ -5101,7 +5224,7 @@ semver-diff@^2.0.0: | |||
5101 | dependencies: | 5224 | dependencies: |
5102 | semver "^5.0.3" | 5225 | semver "^5.0.3" |
5103 | 5226 | ||
5104 | "semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: | 5227 | "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.7.0, semver@^5.7.1: |
5105 | version "5.7.1" | 5228 | version "5.7.1" |
5106 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" | 5229 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" |
5107 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== | 5230 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== |
@@ -5111,11 +5234,16 @@ semver@4.3.2: | |||
5111 | resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" | 5234 | resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" |
5112 | integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c= | 5235 | integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c= |
5113 | 5236 | ||
5114 | semver@^6.3.0: | 5237 | semver@^6.1.0, semver@^6.1.2, semver@^6.3.0: |
5115 | version "6.3.0" | 5238 | version "6.3.0" |
5116 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" | 5239 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" |
5117 | integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== | 5240 | integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== |
5118 | 5241 | ||
5242 | semver@^7.1.1: | ||
5243 | version "7.1.2" | ||
5244 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.2.tgz#847bae5bce68c5d08889824f02667199b70e3d87" | ||
5245 | integrity sha512-BJs9T/H8sEVHbeigqzIEo57Iu/3DG6c4QoqTfbQB3BPA4zgzAomh/Fk9E7QtjWQ8mx2dgA9YCfSF4y9k9bHNpQ== | ||
5246 | |||
5119 | send@0.17.1: | 5247 | send@0.17.1: |
5120 | version "0.17.1" | 5248 | version "0.17.1" |
5121 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" | 5249 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" |
@@ -5188,17 +5316,17 @@ setprototypeof@1.1.1: | |||
5188 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" | 5316 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" |
5189 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== | 5317 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== |
5190 | 5318 | ||
5191 | sharp@^0.23.3: | 5319 | sharp@^0.24.0: |
5192 | version "0.23.4" | 5320 | version "0.24.0" |
5193 | resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.23.4.tgz#ca36067cb6ff7067fa6c77b01651cb9a890f8eb3" | 5321 | resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.24.0.tgz#1200f4bb36ccc2bb36a78f0bcba0302cf1f7a5fd" |
5194 | integrity sha512-fJMagt6cT0UDy9XCsgyLi0eiwWWhQRxbwGmqQT6sY8Av4s0SVsT/deg8fobBQCTDU5iXRgz0rAeXoE2LBZ8g+Q== | 5322 | integrity sha512-kUtQE6+HJnNqO0H6ueOBtRXahktuqydIBaFMvhDelf/KaK9j/adEdjf4Y3+bbjYOa5i6hi2EAa2Y2G9umP4s2g== |
5195 | dependencies: | 5323 | dependencies: |
5196 | color "^3.1.2" | 5324 | color "^3.1.2" |
5197 | detect-libc "^1.0.3" | 5325 | detect-libc "^1.0.3" |
5198 | nan "^2.14.0" | 5326 | nan "^2.14.0" |
5199 | npmlog "^4.1.2" | 5327 | npmlog "^4.1.2" |
5200 | prebuild-install "^5.3.3" | 5328 | prebuild-install "^5.3.3" |
5201 | semver "^6.3.0" | 5329 | semver "^7.1.1" |
5202 | simple-get "^3.1.0" | 5330 | simple-get "^3.1.0" |
5203 | tar "^5.0.5" | 5331 | tar "^5.0.5" |
5204 | tunnel-agent "^0.6.0" | 5332 | tunnel-agent "^0.6.0" |
@@ -5299,15 +5427,14 @@ sitemap@^5.0.0: | |||
5299 | sax "^1.2.4" | 5427 | sax "^1.2.4" |
5300 | xmlbuilder "^13.0.2" | 5428 | xmlbuilder "^13.0.2" |
5301 | 5429 | ||
5302 | slash@^3.0.0: | 5430 | slice-ansi@^2.1.0: |
5303 | version "3.0.0" | 5431 | version "2.1.0" |
5304 | resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" | 5432 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" |
5305 | integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== | 5433 | integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== |
5306 | 5434 | dependencies: | |
5307 | slice-ansi@0.0.4: | 5435 | ansi-styles "^3.2.0" |
5308 | version "0.0.4" | 5436 | astral-regex "^1.0.0" |
5309 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" | 5437 | is-fullwidth-code-point "^2.0.0" |
5310 | integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU= | ||
5311 | 5438 | ||
5312 | smtp-connection@4.0.2: | 5439 | smtp-connection@4.0.2: |
5313 | version "4.0.2" | 5440 | version "4.0.2" |
@@ -5575,11 +5702,6 @@ streamsearch@0.1.2: | |||
5575 | resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" | 5702 | resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" |
5576 | integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= | 5703 | integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= |
5577 | 5704 | ||
5578 | string-argv@^0.3.0: | ||
5579 | version "0.3.1" | ||
5580 | resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" | ||
5581 | integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== | ||
5582 | |||
5583 | string-width@^1.0.1: | 5705 | string-width@^1.0.1: |
5584 | version "1.0.2" | 5706 | version "1.0.2" |
5585 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" | 5707 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" |
@@ -5658,15 +5780,6 @@ string_decoder@~1.1.1: | |||
5658 | dependencies: | 5780 | dependencies: |
5659 | safe-buffer "~5.1.0" | 5781 | safe-buffer "~5.1.0" |
5660 | 5782 | ||
5661 | stringify-object@^3.3.0: | ||
5662 | version "3.3.0" | ||
5663 | resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" | ||
5664 | integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== | ||
5665 | dependencies: | ||
5666 | get-own-enumerable-property-symbols "^3.0.0" | ||
5667 | is-obj "^1.0.1" | ||
5668 | is-regexp "^1.0.0" | ||
5669 | |||
5670 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: | 5783 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: |
5671 | version "3.0.1" | 5784 | version "3.0.1" |
5672 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" | 5785 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" |
@@ -5715,6 +5828,11 @@ strip-json-comments@2.0.1, strip-json-comments@~2.0.1: | |||
5715 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" | 5828 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" |
5716 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= | 5829 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= |
5717 | 5830 | ||
5831 | strip-json-comments@^3.0.1: | ||
5832 | version "3.0.1" | ||
5833 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" | ||
5834 | integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== | ||
5835 | |||
5718 | superagent@^3.8.3: | 5836 | superagent@^3.8.3: |
5719 | version "3.8.3" | 5837 | version "3.8.3" |
5720 | resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" | 5838 | resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" |
@@ -5746,11 +5864,6 @@ supports-color@6.0.0: | |||
5746 | dependencies: | 5864 | dependencies: |
5747 | has-flag "^3.0.0" | 5865 | has-flag "^3.0.0" |
5748 | 5866 | ||
5749 | supports-color@^2.0.0: | ||
5750 | version "2.0.0" | ||
5751 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" | ||
5752 | integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= | ||
5753 | |||
5754 | supports-color@^5.3.0, supports-color@^5.5.0: | 5867 | supports-color@^5.3.0, supports-color@^5.5.0: |
5755 | version "5.5.0" | 5868 | version "5.5.0" |
5756 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" | 5869 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" |
@@ -5772,16 +5885,15 @@ supports-color@^7.1.0: | |||
5772 | dependencies: | 5885 | dependencies: |
5773 | has-flag "^4.0.0" | 5886 | has-flag "^4.0.0" |
5774 | 5887 | ||
5775 | swagger-cli@^2.2.0: | 5888 | swagger-cli@^3.0.1: |
5776 | version "2.3.5" | 5889 | version "3.0.1" |
5777 | resolved "https://registry.yarnpkg.com/swagger-cli/-/swagger-cli-2.3.5.tgz#a7ae08ae9abe4cc4aaab0334c57166a2cb377fd3" | 5890 | resolved "https://registry.yarnpkg.com/swagger-cli/-/swagger-cli-3.0.1.tgz#ed49c5844e9c10d1fd97d8501611846356ca48ed" |
5778 | integrity sha512-UL3S053zT0P9prYJj2zaiokER2KxJh2GWTJ12SbBAJZnlUKJrUZn3qK+zVc/i/bUcyrRRttA4cp8Lzk6cNm0nw== | 5891 | integrity sha512-RkCH3ylYmtNj5cIQCQtP+f01mTcwkGEKXsnIN+Vyiqf8M0SdgPfyjuNJ78hj47xGXCDysCBINQHtP0p8phYSBA== |
5779 | dependencies: | 5892 | dependencies: |
5780 | chalk "^3.0.0" | 5893 | chalk "^3.0.0" |
5781 | js-yaml "^3.13.1" | 5894 | js-yaml "^3.13.1" |
5782 | mkdirp "^0.5.1" | ||
5783 | swagger-parser "^8.0.4" | 5895 | swagger-parser "^8.0.4" |
5784 | yargs "^15.0.2" | 5896 | yargs "^15.1.0" |
5785 | 5897 | ||
5786 | swagger-methods@^2.0.1: | 5898 | swagger-methods@^2.0.1: |
5787 | version "2.0.2" | 5899 | version "2.0.2" |
@@ -5801,10 +5913,15 @@ swagger-parser@^8.0.4: | |||
5801 | swagger-methods "^2.0.1" | 5913 | swagger-methods "^2.0.1" |
5802 | z-schema "^4.2.2" | 5914 | z-schema "^4.2.2" |
5803 | 5915 | ||
5804 | symbol-observable@^1.1.0: | 5916 | table@^5.2.3: |
5805 | version "1.2.0" | 5917 | version "5.4.6" |
5806 | resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" | 5918 | resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" |
5807 | integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== | 5919 | integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== |
5920 | dependencies: | ||
5921 | ajv "^6.10.2" | ||
5922 | lodash "^4.17.14" | ||
5923 | slice-ansi "^2.1.0" | ||
5924 | string-width "^3.0.0" | ||
5808 | 5925 | ||
5809 | tar-fs@^2.0.0: | 5926 | tar-fs@^2.0.0: |
5810 | version "2.0.0" | 5927 | version "2.0.0" |
@@ -5864,6 +5981,11 @@ text-hex@1.0.x: | |||
5864 | resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" | 5981 | resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" |
5865 | integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== | 5982 | integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== |
5866 | 5983 | ||
5984 | text-table@^0.2.0: | ||
5985 | version "0.2.0" | ||
5986 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" | ||
5987 | integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= | ||
5988 | |||
5867 | thirty-two@^1.0.1: | 5989 | thirty-two@^1.0.1: |
5868 | version "1.0.2" | 5990 | version "1.0.2" |
5869 | resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" | 5991 | resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" |
@@ -5893,7 +6015,7 @@ through2@^2.0.3: | |||
5893 | readable-stream "~2.3.6" | 6015 | readable-stream "~2.3.6" |
5894 | xtend "~4.0.1" | 6016 | xtend "~4.0.1" |
5895 | 6017 | ||
5896 | through@2: | 6018 | through@2, through@^2.3.6: |
5897 | version "2.3.8" | 6019 | version "2.3.8" |
5898 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" | 6020 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" |
5899 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= | 6021 | integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= |
@@ -5916,7 +6038,7 @@ timers-ext@^0.1.5: | |||
5916 | es5-ext "~0.10.46" | 6038 | es5-ext "~0.10.46" |
5917 | next-tick "1" | 6039 | next-tick "1" |
5918 | 6040 | ||
5919 | tmp@0.0.x: | 6041 | tmp@0.0.x, tmp@^0.0.33: |
5920 | version "0.0.33" | 6042 | version "0.0.33" |
5921 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" | 6043 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" |
5922 | integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== | 6044 | integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== |
@@ -6006,16 +6128,16 @@ triple-beam@^1.2.0, triple-beam@^1.3.0: | |||
6006 | resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" | 6128 | resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" |
6007 | integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== | 6129 | integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== |
6008 | 6130 | ||
6009 | ts-node@8.5.4: | 6131 | ts-node@8.6.2: |
6010 | version "8.5.4" | 6132 | version "8.6.2" |
6011 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.5.4.tgz#a152add11fa19c221d0b48962c210cf467262ab2" | 6133 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.6.2.tgz#7419a01391a818fbafa6f826a33c1a13e9464e35" |
6012 | integrity sha512-izbVCRV68EasEPQ8MSIGBNK9dc/4sYJJKYA+IarMQct1RtEot6Xp0bXuClsbUSnKpg50ho+aOAx8en5c+y4OFw== | 6134 | integrity sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg== |
6013 | dependencies: | 6135 | dependencies: |
6014 | arg "^4.1.0" | 6136 | arg "^4.1.0" |
6015 | diff "^4.0.1" | 6137 | diff "^4.0.1" |
6016 | make-error "^1.1.1" | 6138 | make-error "^1.1.1" |
6017 | source-map-support "^0.5.6" | 6139 | source-map-support "^0.5.6" |
6018 | yn "^3.0.0" | 6140 | yn "3.1.1" |
6019 | 6141 | ||
6020 | tsconfig-paths@^3.9.0: | 6142 | tsconfig-paths@^3.9.0: |
6021 | version "3.9.0" | 6143 | version "3.9.0" |
@@ -6027,59 +6149,12 @@ tsconfig-paths@^3.9.0: | |||
6027 | minimist "^1.2.0" | 6149 | minimist "^1.2.0" |
6028 | strip-bom "^3.0.0" | 6150 | strip-bom "^3.0.0" |
6029 | 6151 | ||
6030 | tslib@1.9.0: | 6152 | tslib@^1.8.1, tslib@^1.9.0: |
6031 | version "1.9.0" | ||
6032 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" | ||
6033 | integrity sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ== | ||
6034 | |||
6035 | tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: | ||
6036 | version "1.10.0" | 6153 | version "1.10.0" |
6037 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" | 6154 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" |
6038 | integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== | 6155 | integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== |
6039 | 6156 | ||
6040 | tslint-config-standard@^9.0.0: | 6157 | tsutils@^3.17.1: |
6041 | version "9.0.0" | ||
6042 | resolved "https://registry.yarnpkg.com/tslint-config-standard/-/tslint-config-standard-9.0.0.tgz#349a94819d93d5f8d803e3c71cb58ef38eff88e0" | ||
6043 | integrity sha512-CAw9J743RnPMemQV/XQ4YyNreC+A1NItACfkm+cBedrOkz6CQfwlnbKn8anUXBfoa4Zo4tjAhblRbsMNcSLfSw== | ||
6044 | dependencies: | ||
6045 | tslint-eslint-rules "^5.3.1" | ||
6046 | |||
6047 | tslint-eslint-rules@^5.3.1: | ||
6048 | version "5.4.0" | ||
6049 | resolved "https://registry.yarnpkg.com/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz#e488cc9181bf193fe5cd7bfca213a7695f1737b5" | ||
6050 | integrity sha512-WlSXE+J2vY/VPgIcqQuijMQiel+UtmXS+4nvK4ZzlDiqBfXse8FAvkNnTcYhnQyOTW5KFM+uRRGXxYhFpuBc6w== | ||
6051 | dependencies: | ||
6052 | doctrine "0.7.2" | ||
6053 | tslib "1.9.0" | ||
6054 | tsutils "^3.0.0" | ||
6055 | |||
6056 | tslint@^5.7.0: | ||
6057 | version "5.20.1" | ||
6058 | resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d" | ||
6059 | integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg== | ||
6060 | dependencies: | ||
6061 | "@babel/code-frame" "^7.0.0" | ||
6062 | builtin-modules "^1.1.1" | ||
6063 | chalk "^2.3.0" | ||
6064 | commander "^2.12.1" | ||
6065 | diff "^4.0.1" | ||
6066 | glob "^7.1.1" | ||
6067 | js-yaml "^3.13.1" | ||
6068 | minimatch "^3.0.4" | ||
6069 | mkdirp "^0.5.1" | ||
6070 | resolve "^1.3.2" | ||
6071 | semver "^5.3.0" | ||
6072 | tslib "^1.8.0" | ||
6073 | tsutils "^2.29.0" | ||
6074 | |||
6075 | tsutils@^2.29.0: | ||
6076 | version "2.29.0" | ||
6077 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" | ||
6078 | integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== | ||
6079 | dependencies: | ||
6080 | tslib "^1.8.1" | ||
6081 | |||
6082 | tsutils@^3.0.0: | ||
6083 | version "3.17.1" | 6158 | version "3.17.1" |
6084 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" | 6159 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" |
6085 | integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== | 6160 | integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== |
@@ -6103,6 +6178,13 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: | |||
6103 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" | 6178 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" |
6104 | integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= | 6179 | integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= |
6105 | 6180 | ||
6181 | type-check@~0.3.2: | ||
6182 | version "0.3.2" | ||
6183 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" | ||
6184 | integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= | ||
6185 | dependencies: | ||
6186 | prelude-ls "~1.1.2" | ||
6187 | |||
6106 | type-detect@0.1.1: | 6188 | type-detect@0.1.1: |
6107 | version "0.1.1" | 6189 | version "0.1.1" |
6108 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" | 6190 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" |
@@ -6113,6 +6195,11 @@ type-detect@^4.0.0, type-detect@^4.0.5: | |||
6113 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" | 6195 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" |
6114 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== | 6196 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== |
6115 | 6197 | ||
6198 | type-fest@^0.8.1: | ||
6199 | version "0.8.1" | ||
6200 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" | ||
6201 | integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== | ||
6202 | |||
6116 | type-is@1.6.15: | 6203 | type-is@1.6.15: |
6117 | version "1.6.15" | 6204 | version "1.6.15" |
6118 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" | 6205 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" |
@@ -6152,9 +6239,9 @@ typedarray@^0.0.6: | |||
6152 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= | 6239 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= |
6153 | 6240 | ||
6154 | typescript@^3.7.2: | 6241 | typescript@^3.7.2: |
6155 | version "3.7.4" | 6242 | version "3.7.5" |
6156 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19" | 6243 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" |
6157 | integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw== | 6244 | integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== |
6158 | 6245 | ||
6159 | uint64be@^2.0.2: | 6246 | uint64be@^2.0.2: |
6160 | version "2.0.2" | 6247 | version "2.0.2" |
@@ -6272,12 +6359,14 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: | |||
6272 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= | 6359 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= |
6273 | 6360 | ||
6274 | util.promisify@^1.0.0: | 6361 | util.promisify@^1.0.0: |
6275 | version "1.0.0" | 6362 | version "1.0.1" |
6276 | resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" | 6363 | resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" |
6277 | integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== | 6364 | integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== |
6278 | dependencies: | 6365 | dependencies: |
6279 | define-properties "^1.1.2" | 6366 | define-properties "^1.1.3" |
6280 | object.getownpropertydescriptors "^2.0.3" | 6367 | es-abstract "^1.17.2" |
6368 | has-symbols "^1.0.1" | ||
6369 | object.getownpropertydescriptors "^2.1.0" | ||
6281 | 6370 | ||
6282 | utile@0.3.x: | 6371 | utile@0.3.x: |
6283 | version "0.3.0" | 6372 | version "0.3.0" |
@@ -6305,9 +6394,14 @@ uue@^3.1.0: | |||
6305 | extend "~3.0.0" | 6394 | extend "~3.0.0" |
6306 | 6395 | ||
6307 | uuid@^3.1.0, uuid@^3.3.2, uuid@^3.3.3: | 6396 | uuid@^3.1.0, uuid@^3.3.2, uuid@^3.3.3: |
6308 | version "3.3.3" | 6397 | version "3.4.0" |
6309 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" | 6398 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" |
6310 | integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== | 6399 | integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== |
6400 | |||
6401 | v8-compile-cache@^2.0.3: | ||
6402 | version "2.1.0" | ||
6403 | resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" | ||
6404 | integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== | ||
6311 | 6405 | ||
6312 | validate-npm-package-license@^3.0.1: | 6406 | validate-npm-package-license@^3.0.1: |
6313 | version "3.0.4" | 6407 | version "3.0.4" |
@@ -6322,15 +6416,15 @@ validator@^10.11.0: | |||
6322 | resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" | 6416 | resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" |
6323 | integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== | 6417 | integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw== |
6324 | 6418 | ||
6325 | validator@^11.0.0, validator@^11.1.0: | 6419 | validator@^11.0.0: |
6326 | version "11.1.0" | 6420 | version "11.1.0" |
6327 | resolved "https://registry.yarnpkg.com/validator/-/validator-11.1.0.tgz#ac18cac42e0aa5902b603d7a5d9b7827e2346ac4" | 6421 | resolved "https://registry.yarnpkg.com/validator/-/validator-11.1.0.tgz#ac18cac42e0aa5902b603d7a5d9b7827e2346ac4" |
6328 | integrity sha512-qiQ5ktdO7CD6C/5/mYV4jku/7qnqzjrxb3C/Q5wR3vGGinHTgJZN/TdFT3ZX4vXhX2R1PXx42fB1cn5W+uJ4lg== | 6422 | integrity sha512-qiQ5ktdO7CD6C/5/mYV4jku/7qnqzjrxb3C/Q5wR3vGGinHTgJZN/TdFT3ZX4vXhX2R1PXx42fB1cn5W+uJ4lg== |
6329 | 6423 | ||
6330 | validator@^12.1.0: | 6424 | validator@^12.1.0: |
6331 | version "12.1.0" | 6425 | version "12.2.0" |
6332 | resolved "https://registry.yarnpkg.com/validator/-/validator-12.1.0.tgz#a3a7315d5238cbc15e46ad8d5e479aafa7119925" | 6426 | resolved "https://registry.yarnpkg.com/validator/-/validator-12.2.0.tgz#660d47e96267033fd070096c3b1a6f2db4380a0a" |
6333 | integrity sha512-gIC2RBuFRi574Rb9vewGCJ7TCLxHXNx6EKthEgs+Iz0pYa9a9Te1VLG/bGLsAyGWrqR5FfR7tbFUI7FEF2LiGA== | 6427 | integrity sha512-jJfE/DW6tIK1Ek8nCfNFqt8Wb3nzMoAbocBF6/Icgg1ZFSBpObdnwVY2jQj6qUqzhx5jc71fpvBWyLGO7Xl+nQ== |
6334 | 6428 | ||
6335 | vary@^1, vary@~1.1.2: | 6429 | vary@^1, vary@~1.1.2: |
6336 | version "1.1.2" | 6430 | version "1.1.2" |
@@ -6423,14 +6517,14 @@ which-pm-runs@^1.0.0: | |||
6423 | resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" | 6517 | resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" |
6424 | integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= | 6518 | integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= |
6425 | 6519 | ||
6426 | which@1.3.1, which@^1.1.1, which@^1.2.9, which@^1.3.1: | 6520 | which@1.3.1, which@^1.1.1, which@^1.2.9: |
6427 | version "1.3.1" | 6521 | version "1.3.1" |
6428 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" | 6522 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" |
6429 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== | 6523 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== |
6430 | dependencies: | 6524 | dependencies: |
6431 | isexe "^2.0.0" | 6525 | isexe "^2.0.0" |
6432 | 6526 | ||
6433 | which@^2.0.1: | 6527 | which@^2.0.1, which@^2.0.2: |
6434 | version "2.0.2" | 6528 | version "2.0.2" |
6435 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" | 6529 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" |
6436 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== | 6530 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== |
@@ -6499,13 +6593,10 @@ wkx@^0.4.8: | |||
6499 | dependencies: | 6593 | dependencies: |
6500 | "@types/node" "*" | 6594 | "@types/node" "*" |
6501 | 6595 | ||
6502 | wrap-ansi@^3.0.1: | 6596 | word-wrap@~1.2.3: |
6503 | version "3.0.1" | 6597 | version "1.2.3" |
6504 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" | 6598 | resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" |
6505 | integrity sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo= | 6599 | integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== |
6506 | dependencies: | ||
6507 | string-width "^2.1.1" | ||
6508 | strip-ansi "^4.0.0" | ||
6509 | 6600 | ||
6510 | wrap-ansi@^5.1.0: | 6601 | wrap-ansi@^5.1.0: |
6511 | version "5.1.0" | 6602 | version "5.1.0" |
@@ -6539,6 +6630,13 @@ write-file-atomic@^2.0.0: | |||
6539 | imurmurhash "^0.1.4" | 6630 | imurmurhash "^0.1.4" |
6540 | signal-exit "^3.0.2" | 6631 | signal-exit "^3.0.2" |
6541 | 6632 | ||
6633 | write@1.0.3: | ||
6634 | version "1.0.3" | ||
6635 | resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" | ||
6636 | integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== | ||
6637 | dependencies: | ||
6638 | mkdirp "^0.5.1" | ||
6639 | |||
6542 | ws@^7.0.0, ws@^7.1.2: | 6640 | ws@^7.0.0, ws@^7.1.2: |
6543 | version "7.2.1" | 6641 | version "7.2.1" |
6544 | resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e" | 6642 | resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e" |
@@ -6566,20 +6664,6 @@ xhr2@^0.1.4: | |||
6566 | resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" | 6664 | resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" |
6567 | integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= | 6665 | integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= |
6568 | 6666 | ||
6569 | xliff@^4.0.0: | ||
6570 | version "4.3.2" | ||
6571 | resolved "https://registry.yarnpkg.com/xliff/-/xliff-4.3.2.tgz#ef9655abce99f4c60efbc8b6d019c3c55e543315" | ||
6572 | integrity sha512-NmI1Q1Zx8tyMl87XmoQnOPQaR7hvgzHhGArskwmUB6Tvyo0PxPkMq59wlyOtV/fNFEhobQqtW/TkpXvuF0RFng== | ||
6573 | dependencies: | ||
6574 | xml-js "1.6.11" | ||
6575 | |||
6576 | xml-js@1.6.11: | ||
6577 | version "1.6.11" | ||
6578 | resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" | ||
6579 | integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== | ||
6580 | dependencies: | ||
6581 | sax "^1.2.4" | ||
6582 | |||
6583 | xml2js@^0.4.4: | 6667 | xml2js@^0.4.4: |
6584 | version "0.4.23" | 6668 | version "0.4.23" |
6585 | resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" | 6669 | resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" |
@@ -6679,7 +6763,7 @@ yargs@13.3.0, yargs@^13.2.4, yargs@^13.3.0: | |||
6679 | y18n "^4.0.0" | 6763 | y18n "^4.0.0" |
6680 | yargs-parser "^13.1.1" | 6764 | yargs-parser "^13.1.1" |
6681 | 6765 | ||
6682 | yargs@^15.0.2: | 6766 | yargs@^15.1.0: |
6683 | version "15.1.0" | 6767 | version "15.1.0" |
6684 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.1.0.tgz#e111381f5830e863a89550bd4b136bb6a5f37219" | 6768 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.1.0.tgz#e111381f5830e863a89550bd4b136bb6a5f37219" |
6685 | integrity sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg== | 6769 | integrity sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg== |
@@ -6701,15 +6785,15 @@ yeast@0.1.2: | |||
6701 | resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" | 6785 | resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" |
6702 | integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= | 6786 | integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= |
6703 | 6787 | ||
6704 | yn@^3.0.0: | 6788 | yn@3.1.1: |
6705 | version "3.1.1" | 6789 | version "3.1.1" |
6706 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" | 6790 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" |
6707 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== | 6791 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== |
6708 | 6792 | ||
6709 | youtube-dl@^2.0.0: | 6793 | youtube-dl@^3.0.2: |
6710 | version "2.3.0" | 6794 | version "3.0.2" |
6711 | resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-2.3.0.tgz#193d59164e809b2c619b348b7e98b37e6abcf620" | 6795 | resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-3.0.2.tgz#66236bfbdc93127efe3a7f02894ec544b23e8aa7" |
6712 | integrity sha512-92oQDJYaSqLbXZI9GWPalq8fuJdlJGsB6mAQ+uEl127kbCpF5HXea5F046kPxUHQ1OnQ3jHqx0wqZ6ELijVMEw== | 6796 | integrity sha512-LFFfpsYbRLpqKsnb4gzbnyN7fm190tJw3gJVSvfoEfnb/xYIPNT6i9G3jdzPDp/U5cwB3OSq63nUa7rUwxXAGA== |
6713 | dependencies: | 6797 | dependencies: |
6714 | debug "~4.1.1" | 6798 | debug "~4.1.1" |
6715 | execa "~3.2.0" | 6799 | execa "~3.2.0" |