diff options
36 files changed, 273 insertions, 215 deletions
diff --git a/client/e2e/src/po/my-account.ts b/client/e2e/src/po/my-account.ts index 61d42214d..9866953e9 100644 --- a/client/e2e/src/po/my-account.ts +++ b/client/e2e/src/po/my-account.ts | |||
@@ -61,7 +61,7 @@ export class MyAccountPage { | |||
61 | 61 | ||
62 | async goOnAssociatedPlaylistEmbed () { | 62 | async goOnAssociatedPlaylistEmbed () { |
63 | let url = await browser.getCurrentUrl() | 63 | let url = await browser.getCurrentUrl() |
64 | url = url.replace('/videos/watch/playlist/', '/video-playlists/embed/') | 64 | url = url.replace('/w/p/', '/video-playlists/embed/') |
65 | url = url.replace(':3333', ':9001') | 65 | url = url.replace(':3333', ':9001') |
66 | 66 | ||
67 | return browser.get(url) | 67 | return browser.get(url) |
diff --git a/client/e2e/src/po/video-upload.po.ts b/client/e2e/src/po/video-upload.po.ts index ad2acee7f..a248912ed 100644 --- a/client/e2e/src/po/video-upload.po.ts +++ b/client/e2e/src/po/video-upload.po.ts | |||
@@ -41,7 +41,7 @@ export class VideoUploadPage { | |||
41 | 41 | ||
42 | await this.getSecondStepSubmitButton().click() | 42 | await this.getSecondStepSubmitButton().click() |
43 | 43 | ||
44 | return browser.wait(browser.ExpectedConditions.urlContains('/watch/')) | 44 | return browser.wait(browser.ExpectedConditions.urlContains('/w/')) |
45 | } | 45 | } |
46 | 46 | ||
47 | private getSecondStepSubmitButton () { | 47 | private getSecondStepSubmitButton () { |
diff --git a/client/e2e/src/po/video-watch.po.ts b/client/e2e/src/po/video-watch.po.ts index b41fe0882..6d91d241e 100644 --- a/client/e2e/src/po/video-watch.po.ts +++ b/client/e2e/src/po/video-watch.po.ts | |||
@@ -43,7 +43,7 @@ export class VideoWatchPage { | |||
43 | 43 | ||
44 | async goOnAssociatedEmbed () { | 44 | async goOnAssociatedEmbed () { |
45 | let url = await browser.getCurrentUrl() | 45 | let url = await browser.getCurrentUrl() |
46 | url = url.replace('/watch/', '/embed/') | 46 | url = url.replace('/w/', '/embed/') |
47 | url = url.replace(':3333', ':9001') | 47 | url = url.replace(':3333', ':9001') |
48 | 48 | ||
49 | return browser.get(url) | 49 | return browser.get(url) |
@@ -65,7 +65,7 @@ export class VideoWatchPage { | |||
65 | await browser.wait(browser.ExpectedConditions.elementToBeClickable(video)) | 65 | await browser.wait(browser.ExpectedConditions.elementToBeClickable(video)) |
66 | await video.click() | 66 | await video.click() |
67 | 67 | ||
68 | await browser.wait(browser.ExpectedConditions.urlContains('/watch/')) | 68 | await browser.wait(browser.ExpectedConditions.urlContains('/w/')) |
69 | } | 69 | } |
70 | 70 | ||
71 | async clickOnFirstVideo () { | 71 | async clickOnFirstVideo () { |
@@ -78,7 +78,7 @@ export class VideoWatchPage { | |||
78 | const textToReturn = videoName.getText() | 78 | const textToReturn = videoName.getText() |
79 | await video.click() | 79 | await video.click() |
80 | 80 | ||
81 | await browser.wait(browser.ExpectedConditions.urlContains('/watch/')) | 81 | await browser.wait(browser.ExpectedConditions.urlContains('/w/')) |
82 | return textToReturn | 82 | return textToReturn |
83 | } | 83 | } |
84 | 84 | ||
diff --git a/client/e2e/src/videos.e2e-spec.ts b/client/e2e/src/videos.e2e-spec.ts index bcc810297..fc816d1bf 100644 --- a/client/e2e/src/videos.e2e-spec.ts +++ b/client/e2e/src/videos.e2e-spec.ts | |||
@@ -85,7 +85,7 @@ describe('Videos workflow', () => { | |||
85 | let videoNameToExcept = videoName | 85 | let videoNameToExcept = videoName |
86 | 86 | ||
87 | if (await isMobileDevice() || await isSafari()) { | 87 | if (await isMobileDevice() || await isSafari()) { |
88 | await browser.get('https://peertube2.cpy.re/videos/watch/122d093a-1ede-43bd-bd34-59d2931ffc5e') | 88 | await browser.get('https://peertube2.cpy.re/w/122d093a-1ede-43bd-bd34-59d2931ffc5e') |
89 | videoNameToExcept = 'E2E tests' | 89 | videoNameToExcept = 'E2E tests' |
90 | } else { | 90 | } else { |
91 | await videoWatchPage.clickOnVideo(videoName) | 91 | await videoWatchPage.clickOnVideo(videoName) |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html index 451e6a34a..03997ea40 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-basic-configuration.component.html | |||
@@ -489,7 +489,7 @@ | |||
489 | <ng-container i18n> | 489 | <ng-container i18n> |
490 | If your instance is explicitly allowed by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br /> | 490 | If your instance is explicitly allowed by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br /> |
491 | If the instance is not, we use an image link card that will redirect to your PeerTube instance.<br /><br /> | 491 | If the instance is not, we use an image link card that will redirect to your PeerTube instance.<br /><br /> |
492 | Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on | 492 | Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/w/blabla) on |
493 | <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a> | 493 | <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a> |
494 | to see if you instance is allowed. | 494 | to see if you instance is allowed. |
495 | </ng-container> | 495 | </ng-container> |
diff --git a/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts b/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts index 359535526..bb9d70524 100644 --- a/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts +++ b/client/src/app/+my-library/my-video-imports/my-video-imports.component.ts | |||
@@ -55,7 +55,7 @@ export class MyVideoImportsComponent extends RestTable implements OnInit { | |||
55 | } | 55 | } |
56 | 56 | ||
57 | getVideoUrl (video: { uuid: string }) { | 57 | getVideoUrl (video: { uuid: string }) { |
58 | return '/videos/watch/' + video.uuid | 58 | return '/w/' + video.uuid |
59 | } | 59 | } |
60 | 60 | ||
61 | getEditVideoUrl (video: { uuid: string }) { | 61 | getEditVideoUrl (video: { uuid: string }) { |
diff --git a/client/src/app/+page-not-found/page-not-found.component.ts b/client/src/app/+page-not-found/page-not-found.component.ts index 695568898..639e5db78 100644 --- a/client/src/app/+page-not-found/page-not-found.component.ts +++ b/client/src/app/+page-not-found/page-not-found.component.ts | |||
@@ -2,8 +2,6 @@ import { Component, OnInit } from '@angular/core' | |||
2 | import { Title } from '@angular/platform-browser' | 2 | import { Title } from '@angular/platform-browser' |
3 | import { Router } from '@angular/router' | 3 | import { Router } from '@angular/router' |
4 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' | 4 | import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' |
5 | |||
6 | |||
7 | @Component({ | 5 | @Component({ |
8 | selector: 'my-page-not-found', | 6 | selector: 'my-page-not-found', |
9 | templateUrl: './page-not-found.component.html', | 7 | templateUrl: './page-not-found.component.html', |
diff --git a/client/src/app/+remote-interaction/remote-interaction.component.ts b/client/src/app/+remote-interaction/remote-interaction.component.ts index 3ebe62f49..6ddf5b58d 100644 --- a/client/src/app/+remote-interaction/remote-interaction.component.ts +++ b/client/src/app/+remote-interaction/remote-interaction.component.ts | |||
@@ -39,7 +39,7 @@ export class RemoteInteractionComponent implements OnInit { | |||
39 | if (videoResult.data.length !== 0) { | 39 | if (videoResult.data.length !== 0) { |
40 | const video = videoResult.data[0] | 40 | const video = videoResult.data[0] |
41 | 41 | ||
42 | redirectUrl = '/videos/watch/' + video.uuid | 42 | redirectUrl = '/w/' + video.uuid |
43 | } else if (channelResult.data.length !== 0) { | 43 | } else if (channelResult.data.length !== 0) { |
44 | const channel = new VideoChannel(channelResult.data[0]) | 44 | const channel = new VideoChannel(channelResult.data[0]) |
45 | 45 | ||
diff --git a/client/src/app/+search/video-lazy-load.resolver.ts b/client/src/app/+search/video-lazy-load.resolver.ts index d4fe6ed79..e43e0089b 100644 --- a/client/src/app/+search/video-lazy-load.resolver.ts +++ b/client/src/app/+search/video-lazy-load.resolver.ts | |||
@@ -28,7 +28,7 @@ export class VideoLazyLoadResolver implements Resolve<any> { | |||
28 | 28 | ||
29 | const video = result.data[0] | 29 | const video = result.data[0] |
30 | 30 | ||
31 | return this.router.navigateByUrl('/videos/watch/' + video.uuid) | 31 | return this.router.navigateByUrl('/w/' + video.uuid) |
32 | }) | 32 | }) |
33 | ) | 33 | ) |
34 | } | 34 | } |
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts index 8e035b6bb..727bbc32f 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts +++ b/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts | |||
@@ -127,7 +127,7 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView | |||
127 | () => { | 127 | () => { |
128 | this.notifier.success($localize`Live published.`) | 128 | this.notifier.success($localize`Live published.`) |
129 | 129 | ||
130 | this.router.navigate(['/videos/watch', video.uuid]) | 130 | this.router.navigate(['/w', video.uuid]) |
131 | }, | 131 | }, |
132 | 132 | ||
133 | err => { | 133 | err => { |
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts index bca1b6eb6..e20f08879 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts +++ b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts | |||
@@ -244,7 +244,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy | |||
244 | this.isUploadingVideo = false | 244 | this.isUploadingVideo = false |
245 | 245 | ||
246 | this.notifier.success($localize`Video published.`) | 246 | this.notifier.success($localize`Video published.`) |
247 | this.router.navigate([ '/videos/watch', video.uuid ]) | 247 | this.router.navigate([ '/w', video.uuid ]) |
248 | }, | 248 | }, |
249 | 249 | ||
250 | err => { | 250 | err => { |
diff --git a/client/src/app/+videos/+video-edit/video-update.component.html b/client/src/app/+videos/+video-edit/video-update.component.html index 3ce3e623e..9629081e3 100644 --- a/client/src/app/+videos/+video-edit/video-update.component.html +++ b/client/src/app/+videos/+video-edit/video-update.component.html | |||
@@ -1,7 +1,7 @@ | |||
1 | <div class="margin-content"> | 1 | <div class="margin-content"> |
2 | <div class="title-page title-page-single"> | 2 | <div class="title-page title-page-single"> |
3 | <span class="mr-1" i18n>Update</span> | 3 | <span class="mr-1" i18n>Update</span> |
4 | <a [routerLink]="[ '/videos/watch', video.uuid ]">{{ video?.name }}</a> | 4 | <a [routerLink]="[ '/w', video.uuid ]">{{ video?.name }}</a> |
5 | </div> | 5 | </div> |
6 | 6 | ||
7 | <form novalidate [formGroup]="form"> | 7 | <form novalidate [formGroup]="form"> |
diff --git a/client/src/app/+videos/+video-edit/video-update.component.ts b/client/src/app/+videos/+video-edit/video-update.component.ts index 2973c6840..574669a23 100644 --- a/client/src/app/+videos/+video-edit/video-update.component.ts +++ b/client/src/app/+videos/+video-edit/video-update.component.ts | |||
@@ -156,7 +156,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { | |||
156 | this.isUpdatingVideo = false | 156 | this.isUpdatingVideo = false |
157 | this.loadingBar.useRef().complete() | 157 | this.loadingBar.useRef().complete() |
158 | this.notifier.success($localize`Video updated.`) | 158 | this.notifier.success($localize`Video updated.`) |
159 | this.router.navigate([ '/videos/watch', this.video.uuid ]) | 159 | this.router.navigate([ '/w', this.video.uuid ]) |
160 | }, | 160 | }, |
161 | 161 | ||
162 | err => { | 162 | err => { |
diff --git a/client/src/app/+videos/+video-watch/comment/video-comment.component.html b/client/src/app/+videos/+video-watch/comment/video-comment.component.html index fc0d66ffd..06548edc8 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comment.component.html +++ b/client/src/app/+videos/+video-watch/comment/video-comment.component.html | |||
@@ -20,7 +20,7 @@ | |||
20 | </a> | 20 | </a> |
21 | </div> | 21 | </div> |
22 | 22 | ||
23 | <a [routerLink]="['/videos/watch', video.uuid, { 'threadId': comment.threadId }]" class="comment-date" [title]="comment.createdAt"> | 23 | <a [routerLink]="['/w', video.uuid, { 'threadId': comment.threadId }]" class="comment-date" [title]="comment.createdAt"> |
24 | {{ comment.createdAt | myFromNow }} | 24 | {{ comment.createdAt | myFromNow }} |
25 | </a> | 25 | </a> |
26 | </div> | 26 | </div> |
@@ -45,7 +45,7 @@ | |||
45 | <ng-container *ngIf="comment.isDeleted"> | 45 | <ng-container *ngIf="comment.isDeleted"> |
46 | <div class="comment-account-date"> | 46 | <div class="comment-account-date"> |
47 | <span class="comment-account" i18n>Deleted</span> | 47 | <span class="comment-account" i18n>Deleted</span> |
48 | <a [routerLink]="['/videos/watch', video.uuid, { 'threadId': comment.threadId }]" | 48 | <a [routerLink]="['/w', video.uuid, { 'threadId': comment.threadId }]" |
49 | class="comment-date">{{ comment.createdAt | myFromNow }}</a> | 49 | class="comment-date">{{ comment.createdAt | myFromNow }}</a> |
50 | </div> | 50 | </div> |
51 | 51 | ||
diff --git a/client/src/app/+videos/+video-watch/video-watch-routing.module.ts b/client/src/app/+videos/+video-watch/video-watch-routing.module.ts index cb77685c0..657fd10f8 100644 --- a/client/src/app/+videos/+video-watch/video-watch-routing.module.ts +++ b/client/src/app/+videos/+video-watch/video-watch-routing.module.ts | |||
@@ -4,7 +4,7 @@ import { VideoWatchComponent } from './video-watch.component' | |||
4 | 4 | ||
5 | const videoWatchRoutes: Routes = [ | 5 | const videoWatchRoutes: Routes = [ |
6 | { | 6 | { |
7 | path: 'playlist/:playlistId', | 7 | path: 'p/:playlistId', |
8 | component: VideoWatchComponent | 8 | component: VideoWatchComponent |
9 | }, | 9 | }, |
10 | { | 10 | { |
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts index 88c5cef52..0acd44524 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts | |||
@@ -690,7 +690,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
690 | if (this.playlist) { | 690 | if (this.playlist) { |
691 | this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo()) | 691 | this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo()) |
692 | } else if (this.nextVideoUuid) { | 692 | } else if (this.nextVideoUuid) { |
693 | this.router.navigate([ '/videos/watch', this.nextVideoUuid ]) | 693 | this.router.navigate([ '/w', this.nextVideoUuid ]) |
694 | } | 694 | } |
695 | } | 695 | } |
696 | 696 | ||
diff --git a/client/src/app/+videos/videos-routing.module.ts b/client/src/app/+videos/videos-routing.module.ts index f9f476b18..926dfaab0 100644 --- a/client/src/app/+videos/videos-routing.module.ts +++ b/client/src/app/+videos/videos-routing.module.ts | |||
@@ -74,31 +74,6 @@ const videosRoutes: Routes = [ | |||
74 | key: 'local-videos-list' | 74 | key: 'local-videos-list' |
75 | } | 75 | } |
76 | } | 76 | } |
77 | }, | ||
78 | { | ||
79 | path: 'upload', | ||
80 | loadChildren: () => import('@app/+videos/+video-edit/video-add.module').then(m => m.VideoAddModule), | ||
81 | data: { | ||
82 | meta: { | ||
83 | title: $localize`Upload a video` | ||
84 | } | ||
85 | } | ||
86 | }, | ||
87 | { | ||
88 | path: 'update/:uuid', | ||
89 | loadChildren: () => import('@app/+videos/+video-edit/video-update.module').then(m => m.VideoUpdateModule), | ||
90 | data: { | ||
91 | meta: { | ||
92 | title: $localize`Edit a video` | ||
93 | } | ||
94 | } | ||
95 | }, | ||
96 | { | ||
97 | path: 'watch', | ||
98 | loadChildren: () => import('@app/+videos/+video-watch/video-watch.module').then(m => m.VideoWatchModule), | ||
99 | data: { | ||
100 | preload: 3000 | ||
101 | } | ||
102 | } | 77 | } |
103 | ] | 78 | ] |
104 | } | 79 | } |
diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index 444b6f134..e35f540be 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts | |||
@@ -36,16 +36,27 @@ const routes: Routes = [ | |||
36 | loadChildren: () => import('./+signup/+verify-account/verify-account.module').then(m => m.VerifyAccountModule), | 36 | loadChildren: () => import('./+signup/+verify-account/verify-account.module').then(m => m.VerifyAccountModule), |
37 | canActivateChild: [ MetaGuard ] | 37 | canActivateChild: [ MetaGuard ] |
38 | }, | 38 | }, |
39 | |||
40 | { | ||
41 | path: 'accounts', | ||
42 | redirectTo: 'a' | ||
43 | }, | ||
39 | { | 44 | { |
40 | path: 'a', | 45 | path: 'a', |
41 | loadChildren: () => import('./+accounts/accounts.module').then(m => m.AccountsModule), | 46 | loadChildren: () => import('./+accounts/accounts.module').then(m => m.AccountsModule), |
42 | canActivateChild: [ MetaGuard ] | 47 | canActivateChild: [ MetaGuard ] |
43 | }, | 48 | }, |
49 | |||
50 | { | ||
51 | path: 'video-channels', | ||
52 | redirectTo: 'c' | ||
53 | }, | ||
44 | { | 54 | { |
45 | path: 'c', | 55 | path: 'c', |
46 | loadChildren: () => import('./+video-channels/video-channels.module').then(m => m.VideoChannelsModule), | 56 | loadChildren: () => import('./+video-channels/video-channels.module').then(m => m.VideoChannelsModule), |
47 | canActivateChild: [ MetaGuard ] | 57 | canActivateChild: [ MetaGuard ] |
48 | }, | 58 | }, |
59 | |||
49 | { | 60 | { |
50 | path: 'about', | 61 | path: 'about', |
51 | loadChildren: () => import('./+about/about.module').then(m => m.AboutModule), | 62 | loadChildren: () => import('./+about/about.module').then(m => m.AboutModule), |
@@ -71,31 +82,60 @@ const routes: Routes = [ | |||
71 | loadChildren: () => import('./+search/search.module').then(m => m.SearchModule), | 82 | loadChildren: () => import('./+search/search.module').then(m => m.SearchModule), |
72 | canActivateChild: [ MetaGuard ] | 83 | canActivateChild: [ MetaGuard ] |
73 | }, | 84 | }, |
85 | |||
74 | { | 86 | { |
75 | path: 'videos', | 87 | path: 'videos/upload', |
76 | loadChildren: () => import('./+videos/videos.module').then(m => m.VideosModule), | 88 | loadChildren: () => import('@app/+videos/+video-edit/video-add.module').then(m => m.VideoAddModule), |
77 | canActivateChild: [ MetaGuard ] | 89 | data: { |
90 | meta: { | ||
91 | title: $localize`Upload a video` | ||
92 | } | ||
93 | } | ||
78 | }, | 94 | }, |
79 | { | 95 | { |
80 | path: 'remote-interaction', | 96 | path: 'videos/update/:uuid', |
81 | loadChildren: () => import('./+remote-interaction/remote-interaction.module').then(m => m.RemoteInteractionModule), | 97 | loadChildren: () => import('@app/+videos/+video-edit/video-update.module').then(m => m.VideoUpdateModule), |
98 | data: { | ||
99 | meta: { | ||
100 | title: $localize`Edit a video` | ||
101 | } | ||
102 | } | ||
103 | }, | ||
104 | |||
105 | { | ||
106 | path: 'videos/watch/playlist', | ||
107 | redirectTo: 'w/p' | ||
108 | }, | ||
109 | { | ||
110 | path: 'videos/watch', | ||
111 | redirectTo: 'w' | ||
112 | }, | ||
113 | { | ||
114 | path: 'w', | ||
115 | loadChildren: () => import('@app/+videos/+video-watch/video-watch.module').then(m => m.VideoWatchModule), | ||
116 | data: { | ||
117 | preload: 3000 | ||
118 | } | ||
119 | }, | ||
120 | { | ||
121 | path: 'videos', | ||
122 | loadChildren: () => import('./+videos/videos.module').then(m => m.VideosModule), | ||
82 | canActivateChild: [ MetaGuard ] | 123 | canActivateChild: [ MetaGuard ] |
83 | }, | 124 | }, |
84 | { | 125 | { |
85 | path: 'video-playlists/watch', | 126 | path: 'video-playlists/watch', |
86 | redirectTo: 'videos/watch/playlist' | 127 | redirectTo: 'videos/watch/playlist' |
87 | }, | 128 | }, |
129 | |||
88 | { | 130 | { |
89 | path: 'accounts', | 131 | path: 'remote-interaction', |
90 | redirectTo: 'a' | 132 | loadChildren: () => import('./+remote-interaction/remote-interaction.module').then(m => m.RemoteInteractionModule), |
91 | }, | 133 | canActivateChild: [ MetaGuard ] |
92 | { | ||
93 | path: 'video-channels', | ||
94 | redirectTo: 'c' | ||
95 | }, | 134 | }, |
135 | |||
136 | // Matches /@:actorName | ||
96 | { | 137 | { |
97 | matcher: (url): UrlMatchResult => { | 138 | matcher: (url): UrlMatchResult => { |
98 | // Matches /@:actorName | ||
99 | const regex = new RegExp(`^@(${USER_USERNAME_REGEX_CHARACTERS}+)$`) | 139 | const regex = new RegExp(`^@(${USER_USERNAME_REGEX_CHARACTERS}+)$`) |
100 | if (url.length !== 1) return null | 140 | if (url.length !== 1) return null |
101 | 141 | ||
@@ -113,6 +153,7 @@ const routes: Routes = [ | |||
113 | canActivate: [ ActorRedirectGuard ], | 153 | canActivate: [ ActorRedirectGuard ], |
114 | component: EmptyComponent | 154 | component: EmptyComponent |
115 | }, | 155 | }, |
156 | |||
116 | { | 157 | { |
117 | path: '', | 158 | path: '', |
118 | component: EmptyComponent // Avoid 404, app component will redirect dynamically | 159 | component: EmptyComponent // Avoid 404, app component will redirect dynamically |
diff --git a/client/src/app/shared/shared-main/users/user-notification.model.ts b/client/src/app/shared/shared-main/users/user-notification.model.ts index 002a01583..c80bc13b0 100644 --- a/client/src/app/shared/shared-main/users/user-notification.model.ts +++ b/client/src/app/shared/shared-main/users/user-notification.model.ts | |||
@@ -238,7 +238,7 @@ export class UserNotification implements UserNotificationServer { | |||
238 | } | 238 | } |
239 | 239 | ||
240 | private buildVideoUrl (video: { uuid: string }) { | 240 | private buildVideoUrl (video: { uuid: string }) { |
241 | return '/videos/watch/' + video.uuid | 241 | return '/w/' + video.uuid |
242 | } | 242 | } |
243 | 243 | ||
244 | private buildAccountUrl (account: { name: string, host: string }) { | 244 | private buildAccountUrl (account: { name: string, host: string }) { |
diff --git a/client/src/app/shared/shared-main/video/video.model.ts b/client/src/app/shared/shared-main/video/video.model.ts index 526d10e32..e7f739bfe 100644 --- a/client/src/app/shared/shared-main/video/video.model.ts +++ b/client/src/app/shared/shared-main/video/video.model.ts | |||
@@ -88,7 +88,7 @@ export class Video implements VideoServerModel { | |||
88 | pluginData?: any | 88 | pluginData?: any |
89 | 89 | ||
90 | static buildClientUrl (videoUUID: string) { | 90 | static buildClientUrl (videoUUID: string) { |
91 | return '/videos/watch/' + videoUUID | 91 | return '/w/' + videoUUID |
92 | } | 92 | } |
93 | 93 | ||
94 | constructor (hash: VideoServerModel, translations = {}) { | 94 | constructor (hash: VideoServerModel, translations = {}) { |
diff --git a/client/src/app/shared/shared-share-modal/video-share.component.ts b/client/src/app/shared/shared-share-modal/video-share.component.ts index e8760bfcc..2a73e6166 100644 --- a/client/src/app/shared/shared-share-modal/video-share.component.ts +++ b/client/src/app/shared/shared-share-modal/video-share.component.ts | |||
@@ -98,14 +98,14 @@ export class VideoShareComponent { | |||
98 | 98 | ||
99 | getVideoUrl () { | 99 | getVideoUrl () { |
100 | let baseUrl = this.customizations.originUrl ? this.video.originInstanceUrl : window.location.origin | 100 | let baseUrl = this.customizations.originUrl ? this.video.originInstanceUrl : window.location.origin |
101 | baseUrl += '/videos/watch/' + this.video.uuid | 101 | baseUrl += '/w/' + this.video.uuid |
102 | const options = this.getVideoOptions(baseUrl) | 102 | const options = this.getVideoOptions(baseUrl) |
103 | 103 | ||
104 | return buildVideoLink(options) | 104 | return buildVideoLink(options) |
105 | } | 105 | } |
106 | 106 | ||
107 | getPlaylistUrl () { | 107 | getPlaylistUrl () { |
108 | const base = window.location.origin + '/videos/watch/playlist/' + this.playlist.uuid | 108 | const base = window.location.origin + '/w/p/' + this.playlist.uuid |
109 | 109 | ||
110 | if (!this.includeVideoInPlaylist) return base | 110 | if (!this.includeVideoInPlaylist) return base |
111 | 111 | ||
diff --git a/client/src/app/shared/shared-thumbnail/video-thumbnail.component.ts b/client/src/app/shared/shared-thumbnail/video-thumbnail.component.ts index bdede17a3..d5583c29f 100644 --- a/client/src/app/shared/shared-thumbnail/video-thumbnail.component.ts +++ b/client/src/app/shared/shared-thumbnail/video-thumbnail.component.ts | |||
@@ -57,7 +57,7 @@ export class VideoThumbnailComponent { | |||
57 | getVideoRouterLink () { | 57 | getVideoRouterLink () { |
58 | if (this.videoRouterLink) return this.videoRouterLink | 58 | if (this.videoRouterLink) return this.videoRouterLink |
59 | 59 | ||
60 | return [ '/videos/watch', this.video.uuid ] | 60 | return [ '/w', this.video.uuid ] |
61 | } | 61 | } |
62 | 62 | ||
63 | onWatchLaterClick (event: Event) { | 63 | onWatchLaterClick (event: Event) { |
diff --git a/client/src/app/shared/shared-video-comment/video-comment.model.ts b/client/src/app/shared/shared-video-comment/video-comment.model.ts index 1a2fe03db..94d6c5fa8 100644 --- a/client/src/app/shared/shared-video-comment/video-comment.model.ts +++ b/client/src/app/shared/shared-video-comment/video-comment.model.ts | |||
@@ -85,7 +85,7 @@ export class VideoCommentAdmin implements VideoCommentAdminServerModel { | |||
85 | id: hash.video.id, | 85 | id: hash.video.id, |
86 | uuid: hash.video.uuid, | 86 | uuid: hash.video.uuid, |
87 | name: hash.video.name, | 87 | name: hash.video.name, |
88 | localUrl: '/videos/watch/' + hash.video.uuid | 88 | localUrl: '/w/' + hash.video.uuid |
89 | } | 89 | } |
90 | 90 | ||
91 | this.localUrl = this.video.localUrl + ';threadId=' + this.threadId | 91 | this.localUrl = this.video.localUrl + ';threadId=' + this.threadId |
diff --git a/client/src/app/shared/shared-video-miniature/video-miniature.component.ts b/client/src/app/shared/shared-video-miniature/video-miniature.component.ts index b58c118be..aac55a6e9 100644 --- a/client/src/app/shared/shared-video-miniature/video-miniature.component.ts +++ b/client/src/app/shared/shared-video-miniature/video-miniature.component.ts | |||
@@ -125,7 +125,7 @@ export class VideoMiniatureComponent implements OnInit { | |||
125 | 125 | ||
126 | buildVideoLink () { | 126 | buildVideoLink () { |
127 | if (this.videoLinkType === 'internal' || !this.video.url) { | 127 | if (this.videoLinkType === 'internal' || !this.video.url) { |
128 | this.videoRouterLink = [ '/videos/watch', this.video.uuid ] | 128 | this.videoRouterLink = [ '/w', this.video.uuid ] |
129 | return | 129 | return |
130 | } | 130 | } |
131 | 131 | ||
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts b/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts index 7c083ae26..86c281a1e 100644 --- a/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts +++ b/client/src/app/shared/shared-video-playlist/video-playlist-element-miniature.component.ts | |||
@@ -71,7 +71,7 @@ export class VideoPlaylistElementMiniatureComponent implements OnInit { | |||
71 | buildRouterLink () { | 71 | buildRouterLink () { |
72 | if (!this.playlist) return null | 72 | if (!this.playlist) return null |
73 | 73 | ||
74 | return [ '/videos/watch/playlist', this.playlist.uuid ] | 74 | return [ '/w/p', this.playlist.uuid ] |
75 | } | 75 | } |
76 | 76 | ||
77 | buildRouterQuery () { | 77 | buildRouterQuery () { |
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist-miniature.component.ts b/client/src/app/shared/shared-video-playlist/video-playlist-miniature.component.ts index 6b0b1056f..9bbec6038 100644 --- a/client/src/app/shared/shared-video-playlist/video-playlist-miniature.component.ts +++ b/client/src/app/shared/shared-video-playlist/video-playlist-miniature.component.ts | |||
@@ -18,6 +18,6 @@ export class VideoPlaylistMiniatureComponent { | |||
18 | if (this.toManage) return [ '/my-library/video-playlists', this.playlist.uuid ] | 18 | if (this.toManage) return [ '/my-library/video-playlists', this.playlist.uuid ] |
19 | if (this.playlist.videosLength === 0) return null | 19 | if (this.playlist.videosLength === 0) return null |
20 | 20 | ||
21 | return [ '/videos/watch/playlist', this.playlist.uuid ] | 21 | return [ '/w/p', this.playlist.uuid ] |
22 | } | 22 | } |
23 | } | 23 | } |
diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts index 1243526d2..2bb70d1fa 100644 --- a/client/src/assets/player/utils.ts +++ b/client/src/assets/player/utils.ts | |||
@@ -65,7 +65,7 @@ function buildVideoLink (options: { | |||
65 | 65 | ||
66 | const url = baseUrl | 66 | const url = baseUrl |
67 | ? baseUrl | 67 | ? baseUrl |
68 | : window.location.origin + window.location.pathname.replace('/embed/', '/watch/') | 68 | : window.location.origin + window.location.pathname.replace('/embed/', '/w/') |
69 | 69 | ||
70 | const params = generateParams(window.location.search) | 70 | const params = generateParams(window.location.search) |
71 | 71 | ||
@@ -101,7 +101,7 @@ function buildPlaylistLink (options: { | |||
101 | 101 | ||
102 | const url = baseUrl | 102 | const url = baseUrl |
103 | ? baseUrl | 103 | ? baseUrl |
104 | : window.location.origin + window.location.pathname.replace('/video-playlists/embed/', '/videos/watch/playlist/') | 104 | : window.location.origin + window.location.pathname.replace('/video-playlists/embed/', '/w/p/') |
105 | 105 | ||
106 | const params = generateParams(window.location.search) | 106 | const params = generateParams(window.location.search) |
107 | 107 | ||
diff --git a/server/controllers/bots.ts b/server/controllers/bots.ts index 8d1fa72f3..9e92063d4 100644 --- a/server/controllers/bots.ts +++ b/server/controllers/bots.ts | |||
@@ -75,7 +75,7 @@ async function getSitemapLocalVideoUrls () { | |||
75 | }) | 75 | }) |
76 | 76 | ||
77 | return data.map(v => ({ | 77 | return data.map(v => ({ |
78 | url: WEBSERVER.URL + '/videos/watch/' + v.uuid, | 78 | url: WEBSERVER.URL + '/w/' + v.uuid, |
79 | video: [ | 79 | video: [ |
80 | { | 80 | { |
81 | title: v.name, | 81 | title: v.name, |
diff --git a/server/controllers/client.ts b/server/controllers/client.ts index 35e5af9d1..fcccc48e0 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts | |||
@@ -19,8 +19,8 @@ const testEmbedPath = join(distPath, 'standalone', 'videos', 'test-embed.html') | |||
19 | 19 | ||
20 | // Special route that add OpenGraph and oEmbed tags | 20 | // Special route that add OpenGraph and oEmbed tags |
21 | // Do not use a template engine for a so little thing | 21 | // Do not use a template engine for a so little thing |
22 | clientsRouter.use('/videos/watch/playlist/:id', asyncMiddleware(generateWatchPlaylistHtmlPage)) | 22 | clientsRouter.use([ '/w/p/:id', '/videos/watch/playlist/:id' ], asyncMiddleware(generateWatchPlaylistHtmlPage)) |
23 | clientsRouter.use('/videos/watch/:id', asyncMiddleware(generateWatchHtmlPage)) | 23 | clientsRouter.use([ '/w/:id', '/videos/watch/:id' ], asyncMiddleware(generateWatchHtmlPage)) |
24 | clientsRouter.use([ '/accounts/:nameWithHost', '/a/:nameWithHost' ], asyncMiddleware(generateAccountHtmlPage)) | 24 | clientsRouter.use([ '/accounts/:nameWithHost', '/a/:nameWithHost' ], asyncMiddleware(generateAccountHtmlPage)) |
25 | clientsRouter.use([ '/video-channels/:nameWithHost', '/c/:nameWithHost' ], asyncMiddleware(generateVideoChannelHtmlPage)) | 25 | clientsRouter.use([ '/video-channels/:nameWithHost', '/c/:nameWithHost' ], asyncMiddleware(generateVideoChannelHtmlPage)) |
26 | clientsRouter.use('/@:nameWithHost', asyncMiddleware(generateActorHtmlPage)) | 26 | clientsRouter.use('/@:nameWithHost', asyncMiddleware(generateActorHtmlPage)) |
diff --git a/server/controllers/feeds.ts b/server/controllers/feeds.ts index f0717bbbc..865f5c2a1 100644 --- a/server/controllers/feeds.ts +++ b/server/controllers/feeds.ts | |||
@@ -293,7 +293,7 @@ function addVideosToFeed (feed, videos: VideoModel[]) { | |||
293 | feed.addItem({ | 293 | feed.addItem({ |
294 | title: video.name, | 294 | title: video.name, |
295 | id: video.url, | 295 | id: video.url, |
296 | link: WEBSERVER.URL + '/videos/watch/' + video.uuid, | 296 | link: WEBSERVER.URL + '/w/' + video.uuid, |
297 | description: video.getTruncatedDescription(), | 297 | description: video.getTruncatedDescription(), |
298 | content: video.description, | 298 | content: video.description, |
299 | author: [ | 299 | author: [ |
diff --git a/server/middlewares/validators/oembed.ts b/server/middlewares/validators/oembed.ts index 2a7dc257b..165eda6d5 100644 --- a/server/middlewares/validators/oembed.ts +++ b/server/middlewares/validators/oembed.ts | |||
@@ -4,15 +4,29 @@ import { join } from 'path' | |||
4 | import { fetchVideo } from '@server/helpers/video' | 4 | import { fetchVideo } from '@server/helpers/video' |
5 | import { VideoPlaylistModel } from '@server/models/video/video-playlist' | 5 | import { VideoPlaylistModel } from '@server/models/video/video-playlist' |
6 | import { VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' | 6 | import { VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' |
7 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
7 | import { isTestInstance } from '../../helpers/core-utils' | 8 | import { isTestInstance } from '../../helpers/core-utils' |
8 | import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' | 9 | import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc' |
9 | import { logger } from '../../helpers/logger' | 10 | import { logger } from '../../helpers/logger' |
10 | import { WEBSERVER } from '../../initializers/constants' | 11 | import { WEBSERVER } from '../../initializers/constants' |
11 | import { areValidationErrors } from './utils' | 12 | import { areValidationErrors } from './utils' |
12 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
13 | 13 | ||
14 | const startVideoPlaylistsURL = WEBSERVER.SCHEME + '://' + join(WEBSERVER.HOST, 'videos', 'watch', 'playlist') + '/' | 14 | const playlistPaths = [ |
15 | const startVideosURL = WEBSERVER.SCHEME + '://' + join(WEBSERVER.HOST, 'videos', 'watch') + '/' | 15 | join('videos', 'watch', 'playlist'), |
16 | join('w', 'p') | ||
17 | ] | ||
18 | |||
19 | const videoPaths = [ | ||
20 | join('videos', 'watch'), | ||
21 | 'w' | ||
22 | ] | ||
23 | |||
24 | function buildUrls (paths: string[]) { | ||
25 | return paths.map(p => WEBSERVER.SCHEME + '://' + join(WEBSERVER.HOST, p) + '/') | ||
26 | } | ||
27 | |||
28 | const startPlaylistURLs = buildUrls(playlistPaths) | ||
29 | const startVideoURLs = buildUrls(videoPaths) | ||
16 | 30 | ||
17 | const watchRegex = /([^/]+)$/ | 31 | const watchRegex = /([^/]+)$/ |
18 | const isURLOptions = { | 32 | const isURLOptions = { |
@@ -43,8 +57,8 @@ const oembedValidator = [ | |||
43 | 57 | ||
44 | const url = req.query.url as string | 58 | const url = req.query.url as string |
45 | 59 | ||
46 | const isPlaylist = url.startsWith(startVideoPlaylistsURL) | 60 | const isPlaylist = startPlaylistURLs.some(u => url.startsWith(u)) |
47 | const isVideo = isPlaylist ? false : url.startsWith(startVideosURL) | 61 | const isVideo = isPlaylist ? false : startVideoURLs.some(u => url.startsWith(u)) |
48 | 62 | ||
49 | const startIsOk = isVideo || isPlaylist | 63 | const startIsOk = isVideo || isPlaylist |
50 | 64 | ||
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts index c293287d3..98cea1b64 100644 --- a/server/models/video/video-playlist.ts +++ b/server/models/video/video-playlist.ts | |||
@@ -496,7 +496,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli | |||
496 | } | 496 | } |
497 | 497 | ||
498 | getWatchUrl () { | 498 | getWatchUrl () { |
499 | return WEBSERVER.URL + '/videos/watch/playlist/' + this.uuid | 499 | return WEBSERVER.URL + '/w/p/' + this.uuid |
500 | } | 500 | } |
501 | 501 | ||
502 | getEmbedStaticPath () { | 502 | getEmbedStaticPath () { |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index d4a258187..5af907533 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -1920,7 +1920,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1920 | } | 1920 | } |
1921 | 1921 | ||
1922 | getWatchStaticPath () { | 1922 | getWatchStaticPath () { |
1923 | return '/videos/watch/' + this.uuid | 1923 | return '/w/' + this.uuid |
1924 | } | 1924 | } |
1925 | 1925 | ||
1926 | getEmbedStaticPath () { | 1926 | getEmbedStaticPath () { |
diff --git a/server/tests/api/server/services.ts b/server/tests/api/server/services.ts index f0fa91674..ea64e4040 100644 --- a/server/tests/api/server/services.ts +++ b/server/tests/api/server/services.ts | |||
@@ -67,61 +67,67 @@ describe('Test services', function () { | |||
67 | }) | 67 | }) |
68 | 68 | ||
69 | it('Should have a valid oEmbed video response', async function () { | 69 | it('Should have a valid oEmbed video response', async function () { |
70 | const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + video.uuid | 70 | for (const basePath of [ '/videos/watch/', '/w/' ]) { |
71 | 71 | const oembedUrl = 'http://localhost:' + server.port + basePath + video.uuid | |
72 | const res = await getOEmbed(server.url, oembedUrl) | 72 | |
73 | const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + | 73 | const res = await getOEmbed(server.url, oembedUrl) |
74 | `title="${video.name}" src="http://localhost:${server.port}/videos/embed/${video.uuid}" ` + | 74 | const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + |
75 | 'frameborder="0" allowfullscreen></iframe>' | 75 | `title="${video.name}" src="http://localhost:${server.port}/videos/embed/${video.uuid}" ` + |
76 | const expectedThumbnailUrl = 'http://localhost:' + server.port + video.previewPath | 76 | 'frameborder="0" allowfullscreen></iframe>' |
77 | 77 | const expectedThumbnailUrl = 'http://localhost:' + server.port + video.previewPath | |
78 | expect(res.body.html).to.equal(expectedHtml) | 78 | |
79 | expect(res.body.title).to.equal(video.name) | 79 | expect(res.body.html).to.equal(expectedHtml) |
80 | expect(res.body.author_name).to.equal(server.videoChannel.displayName) | 80 | expect(res.body.title).to.equal(video.name) |
81 | expect(res.body.width).to.equal(560) | 81 | expect(res.body.author_name).to.equal(server.videoChannel.displayName) |
82 | expect(res.body.height).to.equal(315) | 82 | expect(res.body.width).to.equal(560) |
83 | expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl) | 83 | expect(res.body.height).to.equal(315) |
84 | expect(res.body.thumbnail_width).to.equal(850) | 84 | expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl) |
85 | expect(res.body.thumbnail_height).to.equal(480) | 85 | expect(res.body.thumbnail_width).to.equal(850) |
86 | expect(res.body.thumbnail_height).to.equal(480) | ||
87 | } | ||
86 | }) | 88 | }) |
87 | 89 | ||
88 | it('Should have a valid playlist oEmbed response', async function () { | 90 | it('Should have a valid playlist oEmbed response', async function () { |
89 | const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/playlist/' + playlistUUID | 91 | for (const basePath of [ '/videos/watch/playlist/', '/w/p/' ]) { |
90 | 92 | const oembedUrl = 'http://localhost:' + server.port + basePath + playlistUUID | |
91 | const res = await getOEmbed(server.url, oembedUrl) | 93 | |
92 | const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + | 94 | const res = await getOEmbed(server.url, oembedUrl) |
93 | `title="${playlistDisplayName}" src="http://localhost:${server.port}/video-playlists/embed/${playlistUUID}" ` + | 95 | const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + |
94 | 'frameborder="0" allowfullscreen></iframe>' | 96 | `title="${playlistDisplayName}" src="http://localhost:${server.port}/video-playlists/embed/${playlistUUID}" ` + |
95 | 97 | 'frameborder="0" allowfullscreen></iframe>' | |
96 | expect(res.body.html).to.equal(expectedHtml) | 98 | |
97 | expect(res.body.title).to.equal('The Life and Times of Scrooge McDuck') | 99 | expect(res.body.html).to.equal(expectedHtml) |
98 | expect(res.body.author_name).to.equal(server.videoChannel.displayName) | 100 | expect(res.body.title).to.equal('The Life and Times of Scrooge McDuck') |
99 | expect(res.body.width).to.equal(560) | 101 | expect(res.body.author_name).to.equal(server.videoChannel.displayName) |
100 | expect(res.body.height).to.equal(315) | 102 | expect(res.body.width).to.equal(560) |
101 | expect(res.body.thumbnail_url).exist | 103 | expect(res.body.height).to.equal(315) |
102 | expect(res.body.thumbnail_width).to.equal(280) | 104 | expect(res.body.thumbnail_url).exist |
103 | expect(res.body.thumbnail_height).to.equal(157) | 105 | expect(res.body.thumbnail_width).to.equal(280) |
106 | expect(res.body.thumbnail_height).to.equal(157) | ||
107 | } | ||
104 | }) | 108 | }) |
105 | 109 | ||
106 | it('Should have a valid oEmbed response with small max height query', async function () { | 110 | it('Should have a valid oEmbed response with small max height query', async function () { |
107 | const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + video.uuid | 111 | for (const basePath of [ '/videos/watch/', '/w/' ]) { |
108 | const format = 'json' | 112 | const oembedUrl = 'http://localhost:' + server.port + basePath + video.uuid |
109 | const maxHeight = 50 | 113 | const format = 'json' |
110 | const maxWidth = 50 | 114 | const maxHeight = 50 |
111 | 115 | const maxWidth = 50 | |
112 | const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth) | 116 | |
113 | const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' + | 117 | const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth) |
114 | `title="${video.name}" src="http://localhost:${server.port}/videos/embed/${video.uuid}" ` + | 118 | const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' + |
115 | 'frameborder="0" allowfullscreen></iframe>' | 119 | `title="${video.name}" src="http://localhost:${server.port}/videos/embed/${video.uuid}" ` + |
116 | 120 | 'frameborder="0" allowfullscreen></iframe>' | |
117 | expect(res.body.html).to.equal(expectedHtml) | 121 | |
118 | expect(res.body.title).to.equal(video.name) | 122 | expect(res.body.html).to.equal(expectedHtml) |
119 | expect(res.body.author_name).to.equal(server.videoChannel.displayName) | 123 | expect(res.body.title).to.equal(video.name) |
120 | expect(res.body.height).to.equal(50) | 124 | expect(res.body.author_name).to.equal(server.videoChannel.displayName) |
121 | expect(res.body.width).to.equal(50) | 125 | expect(res.body.height).to.equal(50) |
122 | expect(res.body).to.not.have.property('thumbnail_url') | 126 | expect(res.body.width).to.equal(50) |
123 | expect(res.body).to.not.have.property('thumbnail_width') | 127 | expect(res.body).to.not.have.property('thumbnail_url') |
124 | expect(res.body).to.not.have.property('thumbnail_height') | 128 | expect(res.body).to.not.have.property('thumbnail_width') |
129 | expect(res.body).to.not.have.property('thumbnail_height') | ||
130 | } | ||
125 | }) | 131 | }) |
126 | 132 | ||
127 | after(async function () { | 133 | after(async function () { |
diff --git a/server/tests/client.ts b/server/tests/client.ts index f33e5c1da..253a95624 100644 --- a/server/tests/client.ts +++ b/server/tests/client.ts | |||
@@ -54,6 +54,9 @@ describe('Test a client controllers', function () { | |||
54 | 54 | ||
55 | const channelDescription = 'my super channel description' | 55 | const channelDescription = 'my super channel description' |
56 | 56 | ||
57 | const watchVideoBasePaths = [ '/videos/watch/', '/w/' ] | ||
58 | const watchPlaylistBasePaths = [ '/videos/watch/playlist/', '/w/p/' ] | ||
59 | |||
57 | before(async function () { | 60 | before(async function () { |
58 | this.timeout(120000) | 61 | this.timeout(120000) |
59 | 62 | ||
@@ -111,35 +114,40 @@ describe('Test a client controllers', function () { | |||
111 | }) | 114 | }) |
112 | 115 | ||
113 | describe('oEmbed', function () { | 116 | describe('oEmbed', function () { |
117 | |||
114 | it('Should have valid oEmbed discovery tags for videos', async function () { | 118 | it('Should have valid oEmbed discovery tags for videos', async function () { |
115 | const path = '/videos/watch/' + servers[0].video.uuid | 119 | for (const basePath of watchVideoBasePaths) { |
116 | const res = await request(servers[0].url) | 120 | const path = basePath + servers[0].video.uuid |
117 | .get(path) | 121 | const res = await request(servers[0].url) |
118 | .set('Accept', 'text/html') | 122 | .get(path) |
119 | .expect(HttpStatusCode.OK_200) | 123 | .set('Accept', 'text/html') |
124 | .expect(HttpStatusCode.OK_200) | ||
120 | 125 | ||
121 | const port = servers[0].port | 126 | const port = servers[0].port |
122 | 127 | ||
123 | const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' + | 128 | const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' + |
124 | `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2F${servers[0].video.uuid}" ` + | 129 | `url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2F${servers[0].video.uuid}" ` + |
125 | `title="${servers[0].video.name}" />` | 130 | `title="${servers[0].video.name}" />` |
126 | 131 | ||
127 | expect(res.text).to.contain(expectedLink) | 132 | expect(res.text).to.contain(expectedLink) |
133 | } | ||
128 | }) | 134 | }) |
129 | 135 | ||
130 | it('Should have valid oEmbed discovery tags for a playlist', async function () { | 136 | it('Should have valid oEmbed discovery tags for a playlist', async function () { |
131 | const res = await request(servers[0].url) | 137 | for (const basePath of watchPlaylistBasePaths) { |
132 | .get('/videos/watch/playlist/' + playlistUUID) | 138 | const res = await request(servers[0].url) |
133 | .set('Accept', 'text/html') | 139 | .get(basePath + playlistUUID) |
134 | .expect(HttpStatusCode.OK_200) | 140 | .set('Accept', 'text/html') |
141 | .expect(HttpStatusCode.OK_200) | ||
135 | 142 | ||
136 | const port = servers[0].port | 143 | const port = servers[0].port |
137 | 144 | ||
138 | const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' + | 145 | const expectedLink = '<link rel="alternate" type="application/json+oembed" href="http://localhost:' + port + '/services/oembed?' + |
139 | `url=http%3A%2F%2Flocalhost%3A${port}%2Fvideos%2Fwatch%2Fplaylist%2F${playlistUUID}" ` + | 146 | `url=http%3A%2F%2Flocalhost%3A${port}%2Fw%2Fp%2F${playlistUUID}" ` + |
140 | `title="${playlistName}" />` | 147 | `title="${playlistName}" />` |
141 | 148 | ||
142 | expect(res.text).to.contain(expectedLink) | 149 | expect(res.text).to.contain(expectedLink) |
150 | } | ||
143 | }) | 151 | }) |
144 | }) | 152 | }) |
145 | 153 | ||
@@ -165,6 +173,26 @@ describe('Test a client controllers', function () { | |||
165 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`) | 173 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/video-channels/${servers[0].videoChannel.name}" />`) |
166 | } | 174 | } |
167 | 175 | ||
176 | async function watchVideoPageTest (path: string) { | ||
177 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) | ||
178 | const text = res.text | ||
179 | |||
180 | expect(text).to.contain(`<meta property="og:title" content="${videoName}" />`) | ||
181 | expect(text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`) | ||
182 | expect(text).to.contain('<meta property="og:type" content="video" />') | ||
183 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/w/${servers[0].video.uuid}" />`) | ||
184 | } | ||
185 | |||
186 | async function watchPlaylistPageTest (path: string) { | ||
187 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) | ||
188 | const text = res.text | ||
189 | |||
190 | expect(text).to.contain(`<meta property="og:title" content="${playlistName}" />`) | ||
191 | expect(text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`) | ||
192 | expect(text).to.contain('<meta property="og:type" content="video" />') | ||
193 | expect(text).to.contain(`<meta property="og:url" content="${servers[0].url}/w/p/${playlistUUID}" />`) | ||
194 | } | ||
195 | |||
168 | it('Should have valid Open Graph tags on the account page', async function () { | 196 | it('Should have valid Open Graph tags on the account page', async function () { |
169 | await accountPageTest('/accounts/' + servers[0].user.username) | 197 | await accountPageTest('/accounts/' + servers[0].user.username) |
170 | await accountPageTest('/a/' + servers[0].user.username) | 198 | await accountPageTest('/a/' + servers[0].user.username) |
@@ -177,40 +205,16 @@ describe('Test a client controllers', function () { | |||
177 | await channelPageTest('/@' + servers[0].videoChannel.name) | 205 | await channelPageTest('/@' + servers[0].videoChannel.name) |
178 | }) | 206 | }) |
179 | 207 | ||
180 | it('Should have valid Open Graph tags on the watch page with video id', async function () { | 208 | it('Should have valid Open Graph tags on the watch page', async function () { |
181 | const res = await request(servers[0].url) | 209 | await watchVideoPageTest('/videos/watch/' + servers[0].video.id) |
182 | .get('/videos/watch/' + servers[0].video.id) | 210 | await watchVideoPageTest('/videos/watch/' + servers[0].video.uuid) |
183 | .set('Accept', 'text/html') | 211 | await watchVideoPageTest('/w/' + servers[0].video.uuid) |
184 | .expect(HttpStatusCode.OK_200) | 212 | await watchVideoPageTest('/w/' + servers[0].video.id) |
185 | |||
186 | expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`) | ||
187 | expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`) | ||
188 | expect(res.text).to.contain('<meta property="og:type" content="video" />') | ||
189 | expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`) | ||
190 | }) | ||
191 | |||
192 | it('Should have valid Open Graph tags on the watch page with video uuid', async function () { | ||
193 | const res = await request(servers[0].url) | ||
194 | .get('/videos/watch/' + servers[0].video.uuid) | ||
195 | .set('Accept', 'text/html') | ||
196 | .expect(HttpStatusCode.OK_200) | ||
197 | |||
198 | expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`) | ||
199 | expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`) | ||
200 | expect(res.text).to.contain('<meta property="og:type" content="video" />') | ||
201 | expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`) | ||
202 | }) | 213 | }) |
203 | 214 | ||
204 | it('Should have valid Open Graph tags on the watch playlist page', async function () { | 215 | it('Should have valid Open Graph tags on the watch playlist page', async function () { |
205 | const res = await request(servers[0].url) | 216 | await watchPlaylistPageTest('/videos/watch/playlist/' + playlistUUID) |
206 | .get('/videos/watch/playlist/' + playlistUUID) | 217 | await watchPlaylistPageTest('/w/p/' + playlistUUID) |
207 | .set('Accept', 'text/html') | ||
208 | .expect(HttpStatusCode.OK_200) | ||
209 | |||
210 | expect(res.text).to.contain(`<meta property="og:title" content="${playlistName}" />`) | ||
211 | expect(res.text).to.contain(`<meta property="og:description" content="${playlistDescription}" />`) | ||
212 | expect(res.text).to.contain('<meta property="og:type" content="video" />') | ||
213 | expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/playlist/${playlistUUID}" />`) | ||
214 | }) | 218 | }) |
215 | }) | 219 | }) |
216 | 220 | ||
@@ -238,28 +242,36 @@ describe('Test a client controllers', function () { | |||
238 | expect(text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`) | 242 | expect(text).to.contain(`<meta property="twitter:description" content="${channelDescription}" />`) |
239 | } | 243 | } |
240 | 244 | ||
241 | it('Should have valid twitter card on the watch video page', async function () { | 245 | async function watchVideoPageTest (path: string) { |
242 | const res = await request(servers[0].url) | 246 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) |
243 | .get('/videos/watch/' + servers[0].video.uuid) | 247 | const text = res.text |
244 | .set('Accept', 'text/html') | ||
245 | .expect(HttpStatusCode.OK_200) | ||
246 | 248 | ||
247 | expect(res.text).to.contain('<meta property="twitter:card" content="summary_large_image" />') | 249 | expect(text).to.contain('<meta property="twitter:card" content="summary_large_image" />') |
248 | expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | 250 | expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') |
249 | expect(res.text).to.contain(`<meta property="twitter:title" content="${videoName}" />`) | 251 | expect(text).to.contain(`<meta property="twitter:title" content="${videoName}" />`) |
250 | expect(res.text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`) | 252 | expect(text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`) |
253 | } | ||
254 | |||
255 | async function watchPlaylistPageTest (path: string) { | ||
256 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) | ||
257 | const text = res.text | ||
258 | |||
259 | expect(text).to.contain('<meta property="twitter:card" content="summary" />') | ||
260 | expect(text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | ||
261 | expect(text).to.contain(`<meta property="twitter:title" content="${playlistName}" />`) | ||
262 | expect(text).to.contain(`<meta property="twitter:description" content="${playlistDescription}" />`) | ||
263 | } | ||
264 | |||
265 | it('Should have valid twitter card on the watch video page', async function () { | ||
266 | await watchVideoPageTest('/videos/watch/' + servers[0].video.id) | ||
267 | await watchVideoPageTest('/videos/watch/' + servers[0].video.uuid) | ||
268 | await watchVideoPageTest('/w/' + servers[0].video.uuid) | ||
269 | await watchVideoPageTest('/w/' + servers[0].video.id) | ||
251 | }) | 270 | }) |
252 | 271 | ||
253 | it('Should have valid twitter card on the watch playlist page', async function () { | 272 | it('Should have valid twitter card on the watch playlist page', async function () { |
254 | const res = await request(servers[0].url) | 273 | await watchPlaylistPageTest('/videos/watch/playlist/' + playlistUUID) |
255 | .get('/videos/watch/playlist/' + playlistUUID) | 274 | await watchPlaylistPageTest('/w/p/' + playlistUUID) |
256 | .set('Accept', 'text/html') | ||
257 | .expect(HttpStatusCode.OK_200) | ||
258 | |||
259 | expect(res.text).to.contain('<meta property="twitter:card" content="summary" />') | ||
260 | expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | ||
261 | expect(res.text).to.contain(`<meta property="twitter:title" content="${playlistName}" />`) | ||
262 | expect(res.text).to.contain(`<meta property="twitter:description" content="${playlistDescription}" />`) | ||
263 | }) | 275 | }) |
264 | 276 | ||
265 | it('Should have valid twitter card on the account page', async function () { | 277 | it('Should have valid twitter card on the account page', async function () { |
@@ -304,24 +316,32 @@ describe('Test a client controllers', function () { | |||
304 | expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />') | 316 | expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />') |
305 | } | 317 | } |
306 | 318 | ||
307 | it('Should have valid twitter card on the watch video page', async function () { | 319 | async function watchVideoPageTest (path: string) { |
308 | const res = await request(servers[0].url) | 320 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) |
309 | .get('/videos/watch/' + servers[0].video.uuid) | 321 | const text = res.text |
310 | .set('Accept', 'text/html') | ||
311 | .expect(HttpStatusCode.OK_200) | ||
312 | 322 | ||
313 | expect(res.text).to.contain('<meta property="twitter:card" content="player" />') | 323 | expect(text).to.contain('<meta property="twitter:card" content="player" />') |
314 | expect(res.text).to.contain('<meta property="twitter:site" content="@Kuja" />') | 324 | expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />') |
325 | } | ||
326 | |||
327 | async function watchPlaylistPageTest (path: string) { | ||
328 | const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 }) | ||
329 | const text = res.text | ||
330 | |||
331 | expect(text).to.contain('<meta property="twitter:card" content="player" />') | ||
332 | expect(text).to.contain('<meta property="twitter:site" content="@Kuja" />') | ||
333 | } | ||
334 | |||
335 | it('Should have valid twitter card on the watch video page', async function () { | ||
336 | await watchVideoPageTest('/videos/watch/' + servers[0].video.id) | ||
337 | await watchVideoPageTest('/videos/watch/' + servers[0].video.uuid) | ||
338 | await watchVideoPageTest('/w/' + servers[0].video.uuid) | ||
339 | await watchVideoPageTest('/w/' + servers[0].video.id) | ||
315 | }) | 340 | }) |
316 | 341 | ||
317 | it('Should have valid twitter card on the watch playlist page', async function () { | 342 | it('Should have valid twitter card on the watch playlist page', async function () { |
318 | const res = await request(servers[0].url) | 343 | await watchPlaylistPageTest('/videos/watch/playlist/' + playlistUUID) |
319 | .get('/videos/watch/playlist/' + playlistUUID) | 344 | await watchPlaylistPageTest('/w/p/' + playlistUUID) |
320 | .set('Accept', 'text/html') | ||
321 | .expect(HttpStatusCode.OK_200) | ||
322 | |||
323 | expect(res.text).to.contain('<meta property="twitter:card" content="player" />') | ||
324 | expect(res.text).to.contain('<meta property="twitter:site" content="@Kuja" />') | ||
325 | }) | 345 | }) |
326 | 346 | ||
327 | it('Should have valid twitter card on the account page', async function () { | 347 | it('Should have valid twitter card on the account page', async function () { |
@@ -378,8 +398,10 @@ describe('Test a client controllers', function () { | |||
378 | }) | 398 | }) |
379 | 399 | ||
380 | it('Should use the original video URL for the canonical tag', async function () { | 400 | it('Should use the original video URL for the canonical tag', async function () { |
381 | const res = await makeHTMLRequest(servers[1].url, '/videos/watch/' + servers[0].video.uuid) | 401 | for (const basePath of watchVideoBasePaths) { |
382 | expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`) | 402 | const res = await makeHTMLRequest(servers[1].url, basePath + servers[0].video.uuid) |
403 | expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`) | ||
404 | } | ||
383 | }) | 405 | }) |
384 | 406 | ||
385 | it('Should use the original account URL for the canonical tag', async function () { | 407 | it('Should use the original account URL for the canonical tag', async function () { |
@@ -403,8 +425,10 @@ describe('Test a client controllers', function () { | |||
403 | }) | 425 | }) |
404 | 426 | ||
405 | it('Should use the original playlist URL for the canonical tag', async function () { | 427 | it('Should use the original playlist URL for the canonical tag', async function () { |
406 | const res = await makeHTMLRequest(servers[1].url, '/videos/watch/playlist/' + playlistUUID) | 428 | for (const basePath of watchPlaylistBasePaths) { |
407 | expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlistUUID}" />`) | 429 | const res = await makeHTMLRequest(servers[1].url, basePath + playlistUUID) |
430 | expect(res.text).to.contain(`<link rel="canonical" href="${servers[0].url}/video-playlists/${playlistUUID}" />`) | ||
431 | } | ||
408 | }) | 432 | }) |
409 | }) | 433 | }) |
410 | 434 | ||
diff --git a/server/tools/peertube-watch.ts b/server/tools/peertube-watch.ts index 6d9cfa3b7..3ca3e242a 100644 --- a/server/tools/peertube-watch.ts +++ b/server/tools/peertube-watch.ts | |||
@@ -30,7 +30,7 @@ function run (url: string, options: program.OptionValues) { | |||
30 | 30 | ||
31 | const cmd = 'node ' + join(__dirname, 'node_modules', 'webtorrent-hybrid', 'bin', 'cmd.js') | 31 | const cmd = 'node ' + join(__dirname, 'node_modules', 'webtorrent-hybrid', 'bin', 'cmd.js') |
32 | const args = ` --${options.gui} ` + | 32 | const args = ` --${options.gui} ` + |
33 | url.replace('videos/watch', 'download/torrents') + | 33 | url.replace(/(\/videos\/watch\/)|\/w\//, '/download/torrents/') + |
34 | `-${options.resolution}.torrent` | 34 | `-${options.resolution}.torrent` |
35 | 35 | ||
36 | try { | 36 | try { |