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 {
async goOnAssociatedPlaylistEmbed () {
let url = await browser.getCurrentUrl()
- url = url.replace('/videos/watch/playlist/', '/video-playlists/embed/')
+ url = url.replace('/w/p/', '/video-playlists/embed/')
url = url.replace(':3333', ':9001')
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 {
await this.getSecondStepSubmitButton().click()
- return browser.wait(browser.ExpectedConditions.urlContains('/watch/'))
+ return browser.wait(browser.ExpectedConditions.urlContains('/w/'))
}
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 {
async goOnAssociatedEmbed () {
let url = await browser.getCurrentUrl()
- url = url.replace('/watch/', '/embed/')
+ url = url.replace('/w/', '/embed/')
url = url.replace(':3333', ':9001')
return browser.get(url)
@@ -65,7 +65,7 @@ export class VideoWatchPage {
await browser.wait(browser.ExpectedConditions.elementToBeClickable(video))
await video.click()
- await browser.wait(browser.ExpectedConditions.urlContains('/watch/'))
+ await browser.wait(browser.ExpectedConditions.urlContains('/w/'))
}
async clickOnFirstVideo () {
@@ -78,7 +78,7 @@ export class VideoWatchPage {
const textToReturn = videoName.getText()
await video.click()
- await browser.wait(browser.ExpectedConditions.urlContains('/watch/'))
+ await browser.wait(browser.ExpectedConditions.urlContains('/w/'))
return textToReturn
}
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', () => {
let videoNameToExcept = videoName
if (await isMobileDevice() || await isSafari()) {
- await browser.get('https://peertube2.cpy.re/videos/watch/122d093a-1ede-43bd-bd34-59d2931ffc5e')
+ await browser.get('https://peertube2.cpy.re/w/122d093a-1ede-43bd-bd34-59d2931ffc5e')
videoNameToExcept = 'E2E tests'
} else {
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 @@
If your instance is explicitly allowed by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.
If the instance is not, we use an image link card that will redirect to your PeerTube instance.
- Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on
+ Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/w/blabla) on
https://cards-dev.twitter.com/validator
to see if you instance is allowed.
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 {
}
getVideoUrl (video: { uuid: string }) {
- return '/videos/watch/' + video.uuid
+ return '/w/' + video.uuid
}
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'
import { Title } from '@angular/platform-browser'
import { Router } from '@angular/router'
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
-
-
@Component({
selector: 'my-page-not-found',
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 {
if (videoResult.data.length !== 0) {
const video = videoResult.data[0]
- redirectUrl = '/videos/watch/' + video.uuid
+ redirectUrl = '/w/' + video.uuid
} else if (channelResult.data.length !== 0) {
const channel = new VideoChannel(channelResult.data[0])
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 {
const video = result.data[0]
- return this.router.navigateByUrl('/videos/watch/' + video.uuid)
+ return this.router.navigateByUrl('/w/' + video.uuid)
})
)
}
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
() => {
this.notifier.success($localize`Live published.`)
- this.router.navigate(['/videos/watch', video.uuid])
+ this.router.navigate(['/w', video.uuid])
},
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
this.isUploadingVideo = false
this.notifier.success($localize`Video published.`)
- this.router.navigate([ '/videos/watch', video.uuid ])
+ this.router.navigate([ '/w', video.uuid ])
},
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 @@
-
@@ -45,7 +45,7 @@
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'
const videoWatchRoutes: Routes = [
{
- path: 'playlist/:playlistId',
+ path: 'p/:playlistId',
component: VideoWatchComponent
},
{
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 {
if (this.playlist) {
this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo())
} else if (this.nextVideoUuid) {
- this.router.navigate([ '/videos/watch', this.nextVideoUuid ])
+ this.router.navigate([ '/w', this.nextVideoUuid ])
}
}
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 = [
key: 'local-videos-list'
}
}
- },
- {
- path: 'upload',
- loadChildren: () => import('@app/+videos/+video-edit/video-add.module').then(m => m.VideoAddModule),
- data: {
- meta: {
- title: $localize`Upload a video`
- }
- }
- },
- {
- path: 'update/:uuid',
- loadChildren: () => import('@app/+videos/+video-edit/video-update.module').then(m => m.VideoUpdateModule),
- data: {
- meta: {
- title: $localize`Edit a video`
- }
- }
- },
- {
- path: 'watch',
- loadChildren: () => import('@app/+videos/+video-watch/video-watch.module').then(m => m.VideoWatchModule),
- data: {
- preload: 3000
- }
}
]
}
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 = [
loadChildren: () => import('./+signup/+verify-account/verify-account.module').then(m => m.VerifyAccountModule),
canActivateChild: [ MetaGuard ]
},
+
+ {
+ path: 'accounts',
+ redirectTo: 'a'
+ },
{
path: 'a',
loadChildren: () => import('./+accounts/accounts.module').then(m => m.AccountsModule),
canActivateChild: [ MetaGuard ]
},
+
+ {
+ path: 'video-channels',
+ redirectTo: 'c'
+ },
{
path: 'c',
loadChildren: () => import('./+video-channels/video-channels.module').then(m => m.VideoChannelsModule),
canActivateChild: [ MetaGuard ]
},
+
{
path: 'about',
loadChildren: () => import('./+about/about.module').then(m => m.AboutModule),
@@ -71,31 +82,60 @@ const routes: Routes = [
loadChildren: () => import('./+search/search.module').then(m => m.SearchModule),
canActivateChild: [ MetaGuard ]
},
+
+ {
+ path: 'videos/upload',
+ loadChildren: () => import('@app/+videos/+video-edit/video-add.module').then(m => m.VideoAddModule),
+ data: {
+ meta: {
+ title: $localize`Upload a video`
+ }
+ }
+ },
+ {
+ path: 'videos/update/:uuid',
+ loadChildren: () => import('@app/+videos/+video-edit/video-update.module').then(m => m.VideoUpdateModule),
+ data: {
+ meta: {
+ title: $localize`Edit a video`
+ }
+ }
+ },
+
+ {
+ path: 'videos/watch/playlist',
+ redirectTo: 'w/p'
+ },
+ {
+ path: 'videos/watch',
+ redirectTo: 'w'
+ },
+ {
+ path: 'w',
+ loadChildren: () => import('@app/+videos/+video-watch/video-watch.module').then(m => m.VideoWatchModule),
+ data: {
+ preload: 3000
+ }
+ },
{
path: 'videos',
loadChildren: () => import('./+videos/videos.module').then(m => m.VideosModule),
canActivateChild: [ MetaGuard ]
},
+ {
+ path: 'video-playlists/watch',
+ redirectTo: 'videos/watch/playlist'
+ },
+
{
path: 'remote-interaction',
loadChildren: () => import('./+remote-interaction/remote-interaction.module').then(m => m.RemoteInteractionModule),
canActivateChild: [ MetaGuard ]
},
- {
- path: 'video-playlists/watch',
- redirectTo: 'videos/watch/playlist'
- },
- {
- path: 'accounts',
- redirectTo: 'a'
- },
- {
- path: 'video-channels',
- redirectTo: 'c'
- },
+
+ // Matches /@:actorName
{
matcher: (url): UrlMatchResult => {
- // Matches /@:actorName
const regex = new RegExp(`^@(${USER_USERNAME_REGEX_CHARACTERS}+)$`)
if (url.length !== 1) return null
@@ -113,6 +153,7 @@ const routes: Routes = [
canActivate: [ ActorRedirectGuard ],
component: EmptyComponent
},
+
{
path: '',
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 {
}
private buildVideoUrl (video: { uuid: string }) {
- return '/videos/watch/' + video.uuid
+ return '/w/' + video.uuid
}
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 {
pluginData?: any
static buildClientUrl (videoUUID: string) {
- return '/videos/watch/' + videoUUID
+ return '/w/' + videoUUID
}
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 {
getVideoUrl () {
let baseUrl = this.customizations.originUrl ? this.video.originInstanceUrl : window.location.origin
- baseUrl += '/videos/watch/' + this.video.uuid
+ baseUrl += '/w/' + this.video.uuid
const options = this.getVideoOptions(baseUrl)
return buildVideoLink(options)
}
getPlaylistUrl () {
- const base = window.location.origin + '/videos/watch/playlist/' + this.playlist.uuid
+ const base = window.location.origin + '/w/p/' + this.playlist.uuid
if (!this.includeVideoInPlaylist) return base
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 {
getVideoRouterLink () {
if (this.videoRouterLink) return this.videoRouterLink
- return [ '/videos/watch', this.video.uuid ]
+ return [ '/w', this.video.uuid ]
}
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 {
id: hash.video.id,
uuid: hash.video.uuid,
name: hash.video.name,
- localUrl: '/videos/watch/' + hash.video.uuid
+ localUrl: '/w/' + hash.video.uuid
}
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 {
buildVideoLink () {
if (this.videoLinkType === 'internal' || !this.video.url) {
- this.videoRouterLink = [ '/videos/watch', this.video.uuid ]
+ this.videoRouterLink = [ '/w', this.video.uuid ]
return
}
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 {
buildRouterLink () {
if (!this.playlist) return null
- return [ '/videos/watch/playlist', this.playlist.uuid ]
+ return [ '/w/p', this.playlist.uuid ]
}
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 {
if (this.toManage) return [ '/my-library/video-playlists', this.playlist.uuid ]
if (this.playlist.videosLength === 0) return null
- return [ '/videos/watch/playlist', this.playlist.uuid ]
+ return [ '/w/p', this.playlist.uuid ]
}
}
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: {
const url = baseUrl
? baseUrl
- : window.location.origin + window.location.pathname.replace('/embed/', '/watch/')
+ : window.location.origin + window.location.pathname.replace('/embed/', '/w/')
const params = generateParams(window.location.search)
@@ -101,7 +101,7 @@ function buildPlaylistLink (options: {
const url = baseUrl
? baseUrl
- : window.location.origin + window.location.pathname.replace('/video-playlists/embed/', '/videos/watch/playlist/')
+ : window.location.origin + window.location.pathname.replace('/video-playlists/embed/', '/w/p/')
const params = generateParams(window.location.search)
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 () {
})
return data.map(v => ({
- url: WEBSERVER.URL + '/videos/watch/' + v.uuid,
+ url: WEBSERVER.URL + '/w/' + v.uuid,
video: [
{
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')
// Special route that add OpenGraph and oEmbed tags
// Do not use a template engine for a so little thing
-clientsRouter.use('/videos/watch/playlist/:id', asyncMiddleware(generateWatchPlaylistHtmlPage))
-clientsRouter.use('/videos/watch/:id', asyncMiddleware(generateWatchHtmlPage))
+clientsRouter.use([ '/w/p/:id', '/videos/watch/playlist/:id' ], asyncMiddleware(generateWatchPlaylistHtmlPage))
+clientsRouter.use([ '/w/:id', '/videos/watch/:id' ], asyncMiddleware(generateWatchHtmlPage))
clientsRouter.use([ '/accounts/:nameWithHost', '/a/:nameWithHost' ], asyncMiddleware(generateAccountHtmlPage))
clientsRouter.use([ '/video-channels/:nameWithHost', '/c/:nameWithHost' ], asyncMiddleware(generateVideoChannelHtmlPage))
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[]) {
feed.addItem({
title: video.name,
id: video.url,
- link: WEBSERVER.URL + '/videos/watch/' + video.uuid,
+ link: WEBSERVER.URL + '/w/' + video.uuid,
description: video.getTruncatedDescription(),
content: video.description,
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'
import { fetchVideo } from '@server/helpers/video'
import { VideoPlaylistModel } from '@server/models/video/video-playlist'
import { VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models'
+import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
import { isTestInstance } from '../../helpers/core-utils'
import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
import { logger } from '../../helpers/logger'
import { WEBSERVER } from '../../initializers/constants'
import { areValidationErrors } from './utils'
-import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
-const startVideoPlaylistsURL = WEBSERVER.SCHEME + '://' + join(WEBSERVER.HOST, 'videos', 'watch', 'playlist') + '/'
-const startVideosURL = WEBSERVER.SCHEME + '://' + join(WEBSERVER.HOST, 'videos', 'watch') + '/'
+const playlistPaths = [
+ join('videos', 'watch', 'playlist'),
+ join('w', 'p')
+]
+
+const videoPaths = [
+ join('videos', 'watch'),
+ 'w'
+]
+
+function buildUrls (paths: string[]) {
+ return paths.map(p => WEBSERVER.SCHEME + '://' + join(WEBSERVER.HOST, p) + '/')
+}
+
+const startPlaylistURLs = buildUrls(playlistPaths)
+const startVideoURLs = buildUrls(videoPaths)
const watchRegex = /([^/]+)$/
const isURLOptions = {
@@ -43,8 +57,8 @@ const oembedValidator = [
const url = req.query.url as string
- const isPlaylist = url.startsWith(startVideoPlaylistsURL)
- const isVideo = isPlaylist ? false : url.startsWith(startVideosURL)
+ const isPlaylist = startPlaylistURLs.some(u => url.startsWith(u))
+ const isVideo = isPlaylist ? false : startVideoURLs.some(u => url.startsWith(u))
const startIsOk = isVideo || isPlaylist
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>> {
}
getWatchStaticPath () {
- return '/videos/watch/' + this.uuid
+ return '/w/' + this.uuid
}
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 () {
})
it('Should have a valid oEmbed video response', async function () {
- const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + video.uuid
+ for (const basePath of [ '/videos/watch/', '/w/' ]) {
+ const oembedUrl = 'http://localhost:' + server.port + basePath + video.uuid
- const res = await getOEmbed(server.url, oembedUrl)
- const expectedHtml = ''
- const expectedThumbnailUrl = 'http://localhost:' + server.port + video.previewPath
+ const res = await getOEmbed(server.url, oembedUrl)
+ const expectedHtml = ''
+ const expectedThumbnailUrl = 'http://localhost:' + server.port + video.previewPath
- expect(res.body.html).to.equal(expectedHtml)
- expect(res.body.title).to.equal(video.name)
- expect(res.body.author_name).to.equal(server.videoChannel.displayName)
- expect(res.body.width).to.equal(560)
- expect(res.body.height).to.equal(315)
- expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl)
- expect(res.body.thumbnail_width).to.equal(850)
- expect(res.body.thumbnail_height).to.equal(480)
+ expect(res.body.html).to.equal(expectedHtml)
+ expect(res.body.title).to.equal(video.name)
+ expect(res.body.author_name).to.equal(server.videoChannel.displayName)
+ expect(res.body.width).to.equal(560)
+ expect(res.body.height).to.equal(315)
+ expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl)
+ expect(res.body.thumbnail_width).to.equal(850)
+ expect(res.body.thumbnail_height).to.equal(480)
+ }
})
it('Should have a valid playlist oEmbed response', async function () {
- const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/playlist/' + playlistUUID
+ for (const basePath of [ '/videos/watch/playlist/', '/w/p/' ]) {
+ const oembedUrl = 'http://localhost:' + server.port + basePath + playlistUUID
- const res = await getOEmbed(server.url, oembedUrl)
- const expectedHtml = ''
+ const res = await getOEmbed(server.url, oembedUrl)
+ const expectedHtml = ''
- expect(res.body.html).to.equal(expectedHtml)
- expect(res.body.title).to.equal('The Life and Times of Scrooge McDuck')
- expect(res.body.author_name).to.equal(server.videoChannel.displayName)
- expect(res.body.width).to.equal(560)
- expect(res.body.height).to.equal(315)
- expect(res.body.thumbnail_url).exist
- expect(res.body.thumbnail_width).to.equal(280)
- expect(res.body.thumbnail_height).to.equal(157)
+ expect(res.body.html).to.equal(expectedHtml)
+ expect(res.body.title).to.equal('The Life and Times of Scrooge McDuck')
+ expect(res.body.author_name).to.equal(server.videoChannel.displayName)
+ expect(res.body.width).to.equal(560)
+ expect(res.body.height).to.equal(315)
+ expect(res.body.thumbnail_url).exist
+ expect(res.body.thumbnail_width).to.equal(280)
+ expect(res.body.thumbnail_height).to.equal(157)
+ }
})
it('Should have a valid oEmbed response with small max height query', async function () {
- const oembedUrl = 'http://localhost:' + server.port + '/videos/watch/' + video.uuid
- const format = 'json'
- const maxHeight = 50
- const maxWidth = 50
+ for (const basePath of [ '/videos/watch/', '/w/' ]) {
+ const oembedUrl = 'http://localhost:' + server.port + basePath + video.uuid
+ const format = 'json'
+ const maxHeight = 50
+ const maxWidth = 50
- const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth)
- const expectedHtml = ''
+ const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth)
+ const expectedHtml = ''
- expect(res.body.html).to.equal(expectedHtml)
- expect(res.body.title).to.equal(video.name)
- expect(res.body.author_name).to.equal(server.videoChannel.displayName)
- expect(res.body.height).to.equal(50)
- expect(res.body.width).to.equal(50)
- expect(res.body).to.not.have.property('thumbnail_url')
- expect(res.body).to.not.have.property('thumbnail_width')
- expect(res.body).to.not.have.property('thumbnail_height')
+ expect(res.body.html).to.equal(expectedHtml)
+ expect(res.body.title).to.equal(video.name)
+ expect(res.body.author_name).to.equal(server.videoChannel.displayName)
+ expect(res.body.height).to.equal(50)
+ expect(res.body.width).to.equal(50)
+ expect(res.body).to.not.have.property('thumbnail_url')
+ expect(res.body).to.not.have.property('thumbnail_width')
+ expect(res.body).to.not.have.property('thumbnail_height')
+ }
})
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 () {
const channelDescription = 'my super channel description'
+ const watchVideoBasePaths = [ '/videos/watch/', '/w/' ]
+ const watchPlaylistBasePaths = [ '/videos/watch/playlist/', '/w/p/' ]
+
before(async function () {
this.timeout(120000)
@@ -111,35 +114,40 @@ describe('Test a client controllers', function () {
})
describe('oEmbed', function () {
+
it('Should have valid oEmbed discovery tags for videos', async function () {
- const path = '/videos/watch/' + servers[0].video.uuid
- const res = await request(servers[0].url)
- .get(path)
- .set('Accept', 'text/html')
- .expect(HttpStatusCode.OK_200)
+ for (const basePath of watchVideoBasePaths) {
+ const path = basePath + servers[0].video.uuid
+ const res = await request(servers[0].url)
+ .get(path)
+ .set('Accept', 'text/html')
+ .expect(HttpStatusCode.OK_200)
- const port = servers[0].port
+ const port = servers[0].port
- const expectedLink = '`
+ const expectedLink = '`
- expect(res.text).to.contain(expectedLink)
+ expect(res.text).to.contain(expectedLink)
+ }
})
it('Should have valid oEmbed discovery tags for a playlist', async function () {
- const res = await request(servers[0].url)
- .get('/videos/watch/playlist/' + playlistUUID)
- .set('Accept', 'text/html')
- .expect(HttpStatusCode.OK_200)
+ for (const basePath of watchPlaylistBasePaths) {
+ const res = await request(servers[0].url)
+ .get(basePath + playlistUUID)
+ .set('Accept', 'text/html')
+ .expect(HttpStatusCode.OK_200)
- const port = servers[0].port
+ const port = servers[0].port
- const expectedLink = '`
+ const expectedLink = '`
- expect(res.text).to.contain(expectedLink)
+ expect(res.text).to.contain(expectedLink)
+ }
})
})
@@ -165,6 +173,26 @@ describe('Test a client controllers', function () {
expect(text).to.contain(``)
}
+ async function watchVideoPageTest (path: string) {
+ const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
+ const text = res.text
+
+ expect(text).to.contain(``)
+ expect(text).to.contain(``)
+ expect(text).to.contain('')
+ expect(text).to.contain(``)
+ }
+
+ async function watchPlaylistPageTest (path: string) {
+ const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
+ const text = res.text
+
+ expect(text).to.contain(``)
+ expect(text).to.contain(``)
+ expect(text).to.contain('')
+ expect(text).to.contain(``)
+ }
+
it('Should have valid Open Graph tags on the account page', async function () {
await accountPageTest('/accounts/' + servers[0].user.username)
await accountPageTest('/a/' + servers[0].user.username)
@@ -177,40 +205,16 @@ describe('Test a client controllers', function () {
await channelPageTest('/@' + servers[0].videoChannel.name)
})
- it('Should have valid Open Graph tags on the watch page with video id', async function () {
- const res = await request(servers[0].url)
- .get('/videos/watch/' + servers[0].video.id)
- .set('Accept', 'text/html')
- .expect(HttpStatusCode.OK_200)
-
- expect(res.text).to.contain(``)
- expect(res.text).to.contain(``)
- expect(res.text).to.contain('')
- expect(res.text).to.contain(``)
- })
-
- it('Should have valid Open Graph tags on the watch page with video uuid', async function () {
- const res = await request(servers[0].url)
- .get('/videos/watch/' + servers[0].video.uuid)
- .set('Accept', 'text/html')
- .expect(HttpStatusCode.OK_200)
-
- expect(res.text).to.contain(``)
- expect(res.text).to.contain(``)
- expect(res.text).to.contain('')
- expect(res.text).to.contain(``)
+ it('Should have valid Open Graph tags on the watch page', async function () {
+ await watchVideoPageTest('/videos/watch/' + servers[0].video.id)
+ await watchVideoPageTest('/videos/watch/' + servers[0].video.uuid)
+ await watchVideoPageTest('/w/' + servers[0].video.uuid)
+ await watchVideoPageTest('/w/' + servers[0].video.id)
})
it('Should have valid Open Graph tags on the watch playlist page', async function () {
- const res = await request(servers[0].url)
- .get('/videos/watch/playlist/' + playlistUUID)
- .set('Accept', 'text/html')
- .expect(HttpStatusCode.OK_200)
-
- expect(res.text).to.contain(``)
- expect(res.text).to.contain(``)
- expect(res.text).to.contain('')
- expect(res.text).to.contain(``)
+ await watchPlaylistPageTest('/videos/watch/playlist/' + playlistUUID)
+ await watchPlaylistPageTest('/w/p/' + playlistUUID)
})
})
@@ -238,28 +242,36 @@ describe('Test a client controllers', function () {
expect(text).to.contain(``)
}
- it('Should have valid twitter card on the watch video page', async function () {
- const res = await request(servers[0].url)
- .get('/videos/watch/' + servers[0].video.uuid)
- .set('Accept', 'text/html')
- .expect(HttpStatusCode.OK_200)
+ async function watchVideoPageTest (path: string) {
+ const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
+ const text = res.text
- expect(res.text).to.contain('')
- expect(res.text).to.contain('')
- expect(res.text).to.contain(``)
- expect(res.text).to.contain(``)
+ expect(text).to.contain('')
+ expect(text).to.contain('')
+ expect(text).to.contain(``)
+ expect(text).to.contain(``)
+ }
+
+ async function watchPlaylistPageTest (path: string) {
+ const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
+ const text = res.text
+
+ expect(text).to.contain('')
+ expect(text).to.contain('')
+ expect(text).to.contain(``)
+ expect(text).to.contain(``)
+ }
+
+ it('Should have valid twitter card on the watch video page', async function () {
+ await watchVideoPageTest('/videos/watch/' + servers[0].video.id)
+ await watchVideoPageTest('/videos/watch/' + servers[0].video.uuid)
+ await watchVideoPageTest('/w/' + servers[0].video.uuid)
+ await watchVideoPageTest('/w/' + servers[0].video.id)
})
it('Should have valid twitter card on the watch playlist page', async function () {
- const res = await request(servers[0].url)
- .get('/videos/watch/playlist/' + playlistUUID)
- .set('Accept', 'text/html')
- .expect(HttpStatusCode.OK_200)
-
- expect(res.text).to.contain('')
- expect(res.text).to.contain('')
- expect(res.text).to.contain(``)
- expect(res.text).to.contain(``)
+ await watchPlaylistPageTest('/videos/watch/playlist/' + playlistUUID)
+ await watchPlaylistPageTest('/w/p/' + playlistUUID)
})
it('Should have valid twitter card on the account page', async function () {
@@ -304,24 +316,32 @@ describe('Test a client controllers', function () {
expect(text).to.contain('')
}
- it('Should have valid twitter card on the watch video page', async function () {
- const res = await request(servers[0].url)
- .get('/videos/watch/' + servers[0].video.uuid)
- .set('Accept', 'text/html')
- .expect(HttpStatusCode.OK_200)
+ async function watchVideoPageTest (path: string) {
+ const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
+ const text = res.text
- expect(res.text).to.contain('')
- expect(res.text).to.contain('')
+ expect(text).to.contain('')
+ expect(text).to.contain('')
+ }
+
+ async function watchPlaylistPageTest (path: string) {
+ const res = await makeGetRequest({ url: servers[0].url, path, accept: 'text/html', statusCodeExpected: HttpStatusCode.OK_200 })
+ const text = res.text
+
+ expect(text).to.contain('')
+ expect(text).to.contain('')
+ }
+
+ it('Should have valid twitter card on the watch video page', async function () {
+ await watchVideoPageTest('/videos/watch/' + servers[0].video.id)
+ await watchVideoPageTest('/videos/watch/' + servers[0].video.uuid)
+ await watchVideoPageTest('/w/' + servers[0].video.uuid)
+ await watchVideoPageTest('/w/' + servers[0].video.id)
})
it('Should have valid twitter card on the watch playlist page', async function () {
- const res = await request(servers[0].url)
- .get('/videos/watch/playlist/' + playlistUUID)
- .set('Accept', 'text/html')
- .expect(HttpStatusCode.OK_200)
-
- expect(res.text).to.contain('')
- expect(res.text).to.contain('')
+ await watchPlaylistPageTest('/videos/watch/playlist/' + playlistUUID)
+ await watchPlaylistPageTest('/w/p/' + playlistUUID)
})
it('Should have valid twitter card on the account page', async function () {
@@ -378,8 +398,10 @@ describe('Test a client controllers', function () {
})
it('Should use the original video URL for the canonical tag', async function () {
- const res = await makeHTMLRequest(servers[1].url, '/videos/watch/' + servers[0].video.uuid)
- expect(res.text).to.contain(``)
+ for (const basePath of watchVideoBasePaths) {
+ const res = await makeHTMLRequest(servers[1].url, basePath + servers[0].video.uuid)
+ expect(res.text).to.contain(``)
+ }
})
it('Should use the original account URL for the canonical tag', async function () {
@@ -403,8 +425,10 @@ describe('Test a client controllers', function () {
})
it('Should use the original playlist URL for the canonical tag', async function () {
- const res = await makeHTMLRequest(servers[1].url, '/videos/watch/playlist/' + playlistUUID)
- expect(res.text).to.contain(``)
+ for (const basePath of watchPlaylistBasePaths) {
+ const res = await makeHTMLRequest(servers[1].url, basePath + playlistUUID)
+ expect(res.text).to.contain(``)
+ }
})
})
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) {
const cmd = 'node ' + join(__dirname, 'node_modules', 'webtorrent-hybrid', 'bin', 'cmd.js')
const args = ` --${options.gui} ` +
- url.replace('videos/watch', 'download/torrents') +
+ url.replace(/(\/videos\/watch\/)|\/w\//, '/download/torrents/') +
`-${options.resolution}.torrent`
try {