Refactor video links building
This commit is contained in:
parent
764b1a14fc
commit
9162fdd363
22 changed files with 136 additions and 67 deletions
|
@ -1,6 +1,6 @@
|
||||||
import { SortMeta } from 'primeng/api'
|
import { SortMeta } from 'primeng/api'
|
||||||
import { switchMap } from 'rxjs/operators'
|
import { switchMap } from 'rxjs/operators'
|
||||||
import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils'
|
import { buildVideoEmbedLink, buildVideoOrPlaylistEmbed, decorateVideoLink } from 'src/assets/player/utils'
|
||||||
import { environment } from 'src/environments/environment'
|
import { environment } from 'src/environments/environment'
|
||||||
import { Component, OnInit } from '@angular/core'
|
import { Component, OnInit } from '@angular/core'
|
||||||
import { DomSanitizer } from '@angular/platform-browser'
|
import { DomSanitizer } from '@angular/platform-browser'
|
||||||
|
@ -147,8 +147,9 @@ export class VideoBlockListComponent extends RestTable implements OnInit {
|
||||||
|
|
||||||
getVideoEmbed (entry: VideoBlacklist) {
|
getVideoEmbed (entry: VideoBlacklist) {
|
||||||
return buildVideoOrPlaylistEmbed(
|
return buildVideoOrPlaylistEmbed(
|
||||||
buildVideoLink({
|
decorateVideoLink({
|
||||||
baseUrl: `${environment.originServerUrl}/videos/embed/${entry.video.uuid}`,
|
url: buildVideoEmbedLink(entry.video, environment.originServerUrl),
|
||||||
|
|
||||||
title: false,
|
title: false,
|
||||||
warningTitle: false
|
warningTitle: false
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</my-help>
|
</my-help>
|
||||||
|
|
||||||
<my-markdown-textarea [truncate]="250" formControlName="description" [markdownVideo]="true"></my-markdown-textarea>
|
<my-markdown-textarea [truncate]="250" formControlName="description" [markdownVideo]="videoToUpdate"></my-markdown-textarea>
|
||||||
|
|
||||||
<div *ngIf="formErrors.description" class="form-error">
|
<div *ngIf="formErrors.description" class="form-error">
|
||||||
{{ formErrors.description }}
|
{{ formErrors.description }}
|
||||||
|
|
|
@ -161,7 +161,7 @@ export class VideoCommentComponent implements OnInit, OnChanges {
|
||||||
// Before HTML rendering restore line feed for markdown list compatibility
|
// Before HTML rendering restore line feed for markdown list compatibility
|
||||||
const commentText = this.comment.text.replace(/<br.?\/?>/g, '\r\n')
|
const commentText = this.comment.text.replace(/<br.?\/?>/g, '\r\n')
|
||||||
const html = await this.markdownService.textMarkdownToHTML(commentText, true, true)
|
const html = await this.markdownService.textMarkdownToHTML(commentText, true, true)
|
||||||
this.sanitizedCommentHTML = this.markdownService.processVideoTimestamps(html)
|
this.sanitizedCommentHTML = this.markdownService.processVideoTimestamps(this.video.shortUUID, html)
|
||||||
this.newParentComments = this.parentComments.concat([ this.comment ])
|
this.newParentComments = this.parentComments.concat([ this.comment ])
|
||||||
|
|
||||||
if (this.comment.account) {
|
if (this.comment.account) {
|
||||||
|
|
|
@ -80,6 +80,7 @@ export class VideoDescriptionComponent implements OnChanges {
|
||||||
|
|
||||||
private async setVideoDescriptionHTML () {
|
private async setVideoDescriptionHTML () {
|
||||||
const html = await this.markdownService.textMarkdownToHTML(this.video.description)
|
const html = await this.markdownService.textMarkdownToHTML(this.video.description)
|
||||||
this.videoHTMLDescription = this.markdownService.processVideoTimestamps(html)
|
|
||||||
|
this.videoHTMLDescription = this.markdownService.processVideoTimestamps(this.video.shortUUID, html)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -582,6 +582,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
videoCaptions: playerCaptions,
|
videoCaptions: playerCaptions,
|
||||||
|
|
||||||
|
videoShortUUID: video.shortUUID,
|
||||||
videoUUID: video.uuid
|
videoUUID: video.uuid
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as MarkdownIt from 'markdown-it'
|
import * as MarkdownIt from 'markdown-it'
|
||||||
import { buildVideoLink } from 'src/assets/player/utils'
|
import { buildVideoLink, decorateVideoLink } from 'src/assets/player/utils'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import {
|
import {
|
||||||
COMPLETE_RULES,
|
COMPLETE_RULES,
|
||||||
|
@ -82,10 +82,14 @@ export class MarkdownService {
|
||||||
return this.render({ name: 'customPageMarkdownIt', markdown, withEmoji: true, additionalAllowedTags })
|
return this.render({ name: 'customPageMarkdownIt', markdown, withEmoji: true, additionalAllowedTags })
|
||||||
}
|
}
|
||||||
|
|
||||||
processVideoTimestamps (html: string) {
|
processVideoTimestamps (videoShortUUID: string, html: string) {
|
||||||
return html.replace(/((\d{1,2}):)?(\d{1,2}):(\d{1,2})/g, function (str, _, h, m, s) {
|
return html.replace(/((\d{1,2}):)?(\d{1,2}):(\d{1,2})/g, function (str, _, h, m, s) {
|
||||||
const t = (3600 * +(h || 0)) + (60 * +(m || 0)) + (+(s || 0))
|
const t = (3600 * +(h || 0)) + (60 * +(m || 0)) + (+(s || 0))
|
||||||
const url = buildVideoLink({ startTime: t })
|
|
||||||
|
const url = decorateVideoLink({
|
||||||
|
url: buildVideoLink({ shortUUID: videoShortUUID }),
|
||||||
|
startTime: t
|
||||||
|
})
|
||||||
return `<a class="video-timestamp" href="${url}">${str}</a>`
|
return `<a class="video-timestamp" href="${url}">${str}</a>`
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as debug from 'debug'
|
import * as debug from 'debug'
|
||||||
import truncate from 'lodash-es/truncate'
|
import truncate from 'lodash-es/truncate'
|
||||||
import { SortMeta } from 'primeng/api'
|
import { SortMeta } from 'primeng/api'
|
||||||
import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils'
|
import { buildVideoEmbedLink, buildVideoOrPlaylistEmbed, decorateVideoLink } from 'src/assets/player/utils'
|
||||||
import { environment } from 'src/environments/environment'
|
import { environment } from 'src/environments/environment'
|
||||||
import { Component, Input, OnInit, ViewChild } from '@angular/core'
|
import { Component, Input, OnInit, ViewChild } from '@angular/core'
|
||||||
import { DomSanitizer } from '@angular/platform-browser'
|
import { DomSanitizer } from '@angular/platform-browser'
|
||||||
|
@ -129,8 +129,8 @@ export class AbuseListTableComponent extends RestTable implements OnInit {
|
||||||
|
|
||||||
getVideoEmbed (abuse: AdminAbuse) {
|
getVideoEmbed (abuse: AdminAbuse) {
|
||||||
return buildVideoOrPlaylistEmbed(
|
return buildVideoOrPlaylistEmbed(
|
||||||
buildVideoLink({
|
decorateVideoLink({
|
||||||
baseUrl: `${environment.originServerUrl}/videos/embed/${abuse.video.uuid}`,
|
url: buildVideoEmbedLink(abuse.video, environment.originServerUrl),
|
||||||
title: false,
|
title: false,
|
||||||
warningTitle: false,
|
warningTitle: false,
|
||||||
startTime: abuse.video.startAt,
|
startTime: abuse.video.startAt,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { buildPlaylistLink, buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils'
|
import { buildPlaylistEmbedLink, buildVideoEmbedLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils'
|
||||||
import { environment } from 'src/environments/environment'
|
import { environment } from 'src/environments/environment'
|
||||||
import { Component, ElementRef, Input, OnInit } from '@angular/core'
|
import { Component, ElementRef, Input, OnInit } from '@angular/core'
|
||||||
import { CustomMarkupComponent } from './shared'
|
import { CustomMarkupComponent } from './shared'
|
||||||
|
@ -17,8 +17,8 @@ export class EmbedMarkupComponent implements CustomMarkupComponent, OnInit {
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
const link = this.type === 'video'
|
const link = this.type === 'video'
|
||||||
? buildVideoLink({ baseUrl: `${environment.originServerUrl}/videos/embed/${this.uuid}` })
|
? buildVideoEmbedLink({ uuid: this.uuid }, environment.originServerUrl)
|
||||||
: buildPlaylistLink({ baseUrl: `${environment.originServerUrl}/video-playlists/embed/${this.uuid}` })
|
: buildPlaylistEmbedLink({ uuid: this.uuid }, environment.originServerUrl)
|
||||||
|
|
||||||
this.el.nativeElement.innerHTML = buildVideoOrPlaylistEmbed(link, this.uuid)
|
this.el.nativeElement.innerHTML = buildVideoOrPlaylistEmbed(link, this.uuid)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@an
|
||||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
|
||||||
import { SafeHtml } from '@angular/platform-browser'
|
import { SafeHtml } from '@angular/platform-browser'
|
||||||
import { MarkdownService, ScreenService } from '@app/core'
|
import { MarkdownService, ScreenService } from '@app/core'
|
||||||
|
import { Video } from '@shared/models'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-markdown-textarea',
|
selector: 'my-markdown-textarea',
|
||||||
|
@ -33,7 +34,7 @@ export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit {
|
||||||
@Input() markdownType: 'text' | 'enhanced' = 'text'
|
@Input() markdownType: 'text' | 'enhanced' = 'text'
|
||||||
@Input() customMarkdownRenderer?: (text: string) => Promise<string | HTMLElement>
|
@Input() customMarkdownRenderer?: (text: string) => Promise<string | HTMLElement>
|
||||||
|
|
||||||
@Input() markdownVideo = false
|
@Input() markdownVideo: Video
|
||||||
|
|
||||||
@Input() name = 'description'
|
@Input() name = 'description'
|
||||||
|
|
||||||
|
@ -147,7 +148,7 @@ export class MarkdownTextareaComponent implements ControlValueAccessor, OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.markdownVideo) {
|
if (this.markdownVideo) {
|
||||||
html = this.markdownService.processVideoTimestamps(html)
|
html = this.markdownService.processVideoTimestamps(this.markdownVideo.shortUUID, html)
|
||||||
}
|
}
|
||||||
|
|
||||||
return html
|
return html
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { mapValues, pickBy } from 'lodash-es'
|
import { mapValues, pickBy } from 'lodash-es'
|
||||||
import { buildVideoLink, buildVideoOrPlaylistEmbed } from 'src/assets/player/utils'
|
import { buildVideoOrPlaylistEmbed, decorateVideoLink } from 'src/assets/player/utils'
|
||||||
import { Component, Input, OnInit, ViewChild } from '@angular/core'
|
import { Component, Input, OnInit, ViewChild } from '@angular/core'
|
||||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
|
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
|
||||||
import { Notifier } from '@app/core'
|
import { Notifier } from '@app/core'
|
||||||
|
@ -57,11 +57,12 @@ export class VideoReportComponent extends FormReactive implements OnInit {
|
||||||
getVideoEmbed () {
|
getVideoEmbed () {
|
||||||
return this.sanitizer.bypassSecurityTrustHtml(
|
return this.sanitizer.bypassSecurityTrustHtml(
|
||||||
buildVideoOrPlaylistEmbed(
|
buildVideoOrPlaylistEmbed(
|
||||||
buildVideoLink({
|
decorateVideoLink({
|
||||||
baseUrl: this.video.embedUrl,
|
url: this.video.embedUrl,
|
||||||
title: false,
|
title: false,
|
||||||
warningTitle: false
|
warningTitle: false
|
||||||
}),
|
}),
|
||||||
|
|
||||||
this.video.name
|
this.video.name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
import { Component, ElementRef, Input, ViewChild } from '@angular/core'
|
import { Component, ElementRef, Input, ViewChild } from '@angular/core'
|
||||||
import { Video, VideoDetails } from '@app/shared/shared-main'
|
import { VideoDetails } from '@app/shared/shared-main'
|
||||||
import { VideoPlaylist } from '@app/shared/shared-video-playlist'
|
import { VideoPlaylist } from '@app/shared/shared-video-playlist'
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { VideoCaption } from '@shared/models'
|
import { VideoCaption } from '@shared/models'
|
||||||
import { buildPlaylistLink, buildVideoLink, buildVideoOrPlaylistEmbed } from '../../../assets/player/utils'
|
import {
|
||||||
|
buildPlaylistLink,
|
||||||
|
buildVideoLink,
|
||||||
|
buildVideoOrPlaylistEmbed,
|
||||||
|
decoratePlaylistLink,
|
||||||
|
decorateVideoLink
|
||||||
|
} from '../../../assets/player/utils'
|
||||||
|
|
||||||
type Customizations = {
|
type Customizations = {
|
||||||
startAtCheckbox: boolean
|
startAtCheckbox: boolean
|
||||||
|
@ -83,34 +89,34 @@ export class VideoShareComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideoIframeCode () {
|
getVideoIframeCode () {
|
||||||
const options = this.getVideoOptions(this.video.embedUrl)
|
const embedUrl = decorateVideoLink({ url: this.video.embedUrl, ...this.getVideoOptions() })
|
||||||
|
|
||||||
const embedUrl = buildVideoLink(options)
|
|
||||||
return buildVideoOrPlaylistEmbed(embedUrl, this.video.name)
|
return buildVideoOrPlaylistEmbed(embedUrl, this.video.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlaylistIframeCode () {
|
getPlaylistIframeCode () {
|
||||||
const options = this.getPlaylistOptions(this.playlist.embedUrl)
|
const embedUrl = decoratePlaylistLink({ url: this.playlist.embedUrl, ...this.getPlaylistOptions() })
|
||||||
|
|
||||||
const embedUrl = buildPlaylistLink(options)
|
|
||||||
return buildVideoOrPlaylistEmbed(embedUrl, this.playlist.displayName)
|
return buildVideoOrPlaylistEmbed(embedUrl, this.playlist.displayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
getVideoUrl () {
|
getVideoUrl () {
|
||||||
let baseUrl = this.customizations.originUrl ? this.video.originInstanceUrl : window.location.origin
|
const baseUrl = this.customizations.originUrl
|
||||||
baseUrl += Video.buildWatchUrl(this.video)
|
? this.video.originInstanceUrl
|
||||||
|
: window.location.origin
|
||||||
|
|
||||||
const options = this.getVideoOptions(baseUrl)
|
return decorateVideoLink({
|
||||||
|
url: buildVideoLink(this.video, baseUrl),
|
||||||
|
|
||||||
return buildVideoLink(options)
|
...this.getVideoOptions()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlaylistUrl () {
|
getPlaylistUrl () {
|
||||||
const base = window.location.origin + VideoPlaylist.buildWatchUrl(this.playlist)
|
const url = buildPlaylistLink(this.playlist)
|
||||||
|
if (!this.includeVideoInPlaylist) return url
|
||||||
|
|
||||||
if (!this.includeVideoInPlaylist) return base
|
return decoratePlaylistLink({ url, playlistPosition: this.playlistPosition })
|
||||||
|
|
||||||
return base + '?playlistPosition=' + this.playlistPosition
|
|
||||||
}
|
}
|
||||||
|
|
||||||
notSecure () {
|
notSecure () {
|
||||||
|
@ -133,10 +139,8 @@ export class VideoShareComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getVideoOptions (baseUrl?: string) {
|
private getVideoOptions () {
|
||||||
return {
|
return {
|
||||||
baseUrl,
|
|
||||||
|
|
||||||
startTime: this.customizations.startAtCheckbox ? this.customizations.startAt : undefined,
|
startTime: this.customizations.startAtCheckbox ? this.customizations.startAt : undefined,
|
||||||
stopTime: this.customizations.stopAtCheckbox ? this.customizations.stopAt : undefined,
|
stopTime: this.customizations.stopAtCheckbox ? this.customizations.stopAt : undefined,
|
||||||
|
|
||||||
|
|
|
@ -33,13 +33,14 @@ import { getStoredP2PEnabled } from './peertube-player-local-storage'
|
||||||
import {
|
import {
|
||||||
NextPreviousVideoButtonOptions,
|
NextPreviousVideoButtonOptions,
|
||||||
P2PMediaLoaderPluginOptions,
|
P2PMediaLoaderPluginOptions,
|
||||||
|
PeerTubeLinkButtonOptions,
|
||||||
PlaylistPluginOptions,
|
PlaylistPluginOptions,
|
||||||
UserWatching,
|
UserWatching,
|
||||||
VideoJSCaption,
|
VideoJSCaption,
|
||||||
VideoJSPluginOptions
|
VideoJSPluginOptions
|
||||||
} from './peertube-videojs-typings'
|
} from './peertube-videojs-typings'
|
||||||
import { TranslationsManager } from './translations-manager'
|
import { TranslationsManager } from './translations-manager'
|
||||||
import { buildVideoLink, buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isSafari } from './utils'
|
import { buildVideoLink, buildVideoOrPlaylistEmbed, decorateVideoLink, getRtcConfig, isIOS, isSafari } from './utils'
|
||||||
|
|
||||||
// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
|
// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
|
||||||
(videojs.getComponent('PlaybackRateMenuButton') as any).prototype.controlText_ = 'Speed'
|
(videojs.getComponent('PlaybackRateMenuButton') as any).prototype.controlText_ = 'Speed'
|
||||||
|
@ -110,6 +111,7 @@ export interface CommonOptions extends CustomizationOptions {
|
||||||
videoCaptions: VideoJSCaption[]
|
videoCaptions: VideoJSCaption[]
|
||||||
|
|
||||||
videoUUID: string
|
videoUUID: string
|
||||||
|
videoShortUUID: string
|
||||||
|
|
||||||
userWatching?: UserWatching
|
userWatching?: UserWatching
|
||||||
|
|
||||||
|
@ -175,7 +177,13 @@ export class PeertubePlayerManager {
|
||||||
PeertubePlayerManager.alreadyPlayed = true
|
PeertubePlayerManager.alreadyPlayed = true
|
||||||
})
|
})
|
||||||
|
|
||||||
self.addContextMenu(mode, player, options.common.embedUrl, options.common.embedTitle)
|
self.addContextMenu({
|
||||||
|
mode,
|
||||||
|
player,
|
||||||
|
videoShortUUID: options.common.videoShortUUID,
|
||||||
|
videoEmbedUrl: options.common.embedUrl,
|
||||||
|
videoEmbedTitle: options.common.embedTitle
|
||||||
|
})
|
||||||
|
|
||||||
player.bezels()
|
player.bezels()
|
||||||
player.stats({
|
player.stats({
|
||||||
|
@ -218,7 +226,13 @@ export class PeertubePlayerManager {
|
||||||
videojs(newVideoElement, videojsOptions, function (this: videojs.Player) {
|
videojs(newVideoElement, videojsOptions, function (this: videojs.Player) {
|
||||||
const player = this
|
const player = this
|
||||||
|
|
||||||
self.addContextMenu(mode, player, options.common.embedUrl, options.common.embedTitle)
|
self.addContextMenu({
|
||||||
|
mode,
|
||||||
|
player,
|
||||||
|
videoShortUUID: options.common.videoShortUUID,
|
||||||
|
videoEmbedUrl: options.common.embedUrl,
|
||||||
|
videoEmbedTitle: options.common.embedTitle
|
||||||
|
})
|
||||||
|
|
||||||
PeertubePlayerManager.onPlayerChange(player)
|
PeertubePlayerManager.onPlayerChange(player)
|
||||||
})
|
})
|
||||||
|
@ -295,6 +309,8 @@ export class PeertubePlayerManager {
|
||||||
|
|
||||||
controlBar: {
|
controlBar: {
|
||||||
children: this.getControlBarChildren(mode, {
|
children: this.getControlBarChildren(mode, {
|
||||||
|
videoShortUUID: commonOptions.videoShortUUID,
|
||||||
|
|
||||||
captions: commonOptions.captions,
|
captions: commonOptions.captions,
|
||||||
peertubeLink: commonOptions.peertubeLink,
|
peertubeLink: commonOptions.peertubeLink,
|
||||||
theaterButton: commonOptions.theaterButton,
|
theaterButton: commonOptions.theaterButton,
|
||||||
|
@ -409,6 +425,8 @@ export class PeertubePlayerManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static getControlBarChildren (mode: PlayerMode, options: {
|
private static getControlBarChildren (mode: PlayerMode, options: {
|
||||||
|
videoShortUUID: string
|
||||||
|
|
||||||
peertubeLink: boolean
|
peertubeLink: boolean
|
||||||
theaterButton: boolean
|
theaterButton: boolean
|
||||||
captions: boolean
|
captions: boolean
|
||||||
|
@ -497,7 +515,7 @@ export class PeertubePlayerManager {
|
||||||
|
|
||||||
if (options.peertubeLink === true) {
|
if (options.peertubeLink === true) {
|
||||||
Object.assign(children, {
|
Object.assign(children, {
|
||||||
'peerTubeLinkButton': {}
|
'peerTubeLinkButton': { shortUUID: options.videoShortUUID } as PeerTubeLinkButtonOptions
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,7 +532,15 @@ export class PeertubePlayerManager {
|
||||||
return children
|
return children
|
||||||
}
|
}
|
||||||
|
|
||||||
private static addContextMenu (mode: PlayerMode, player: videojs.Player, videoEmbedUrl: string, videoEmbedTitle: string) {
|
private static addContextMenu (options: {
|
||||||
|
mode: PlayerMode
|
||||||
|
player: videojs.Player
|
||||||
|
videoShortUUID: string
|
||||||
|
videoEmbedUrl: string
|
||||||
|
videoEmbedTitle: string
|
||||||
|
}) {
|
||||||
|
const { mode, player, videoEmbedTitle, videoEmbedUrl, videoShortUUID } = options
|
||||||
|
|
||||||
const content = () => {
|
const content = () => {
|
||||||
const isLoopEnabled = player.options_['loop']
|
const isLoopEnabled = player.options_['loop']
|
||||||
const items = [
|
const items = [
|
||||||
|
@ -528,13 +554,15 @@ export class PeertubePlayerManager {
|
||||||
{
|
{
|
||||||
label: player.localize('Copy the video URL'),
|
label: player.localize('Copy the video URL'),
|
||||||
listener: function () {
|
listener: function () {
|
||||||
copyToClipboard(buildVideoLink())
|
copyToClipboard(buildVideoLink({ shortUUID: videoShortUUID }))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: player.localize('Copy the video URL at the current time'),
|
label: player.localize('Copy the video URL at the current time'),
|
||||||
listener: function (this: videojs.Player) {
|
listener: function (this: videojs.Player) {
|
||||||
copyToClipboard(buildVideoLink({ startTime: this.currentTime() }))
|
const url = buildVideoLink({ shortUUID: videoShortUUID })
|
||||||
|
|
||||||
|
copyToClipboard(decorateVideoLink({ url, startTime: this.currentTime() }))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -132,6 +132,10 @@ type NextPreviousVideoButtonOptions = {
|
||||||
isDisabled: () => boolean
|
isDisabled: () => boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PeerTubeLinkButtonOptions = {
|
||||||
|
shortUUID: string
|
||||||
|
}
|
||||||
|
|
||||||
type WebtorrentPluginOptions = {
|
type WebtorrentPluginOptions = {
|
||||||
playerElement: HTMLVideoElement
|
playerElement: HTMLVideoElement
|
||||||
|
|
||||||
|
@ -225,5 +229,6 @@ export {
|
||||||
VideoJSPluginOptions,
|
VideoJSPluginOptions,
|
||||||
LoadedQualityData,
|
LoadedQualityData,
|
||||||
QualityLevelRepresentation,
|
QualityLevelRepresentation,
|
||||||
|
PeerTubeLinkButtonOptions,
|
||||||
QualityLevels
|
QualityLevels
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { VideoFile } from '@shared/models'
|
import { Video, VideoFile, VideoPlaylist } from '@shared/models'
|
||||||
import { escapeHTML } from '@shared/core-utils/renderer'
|
import { escapeHTML } from '@shared/core-utils/renderer'
|
||||||
|
|
||||||
function toTitleCase (str: string) {
|
function toTitleCase (str: string) {
|
||||||
|
@ -43,8 +43,24 @@ function isMobile () {
|
||||||
return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
|
return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildVideoLink (options: {
|
function buildPlaylistLink (playlist: Pick<VideoPlaylist, 'shortUUID'>, base?: string) {
|
||||||
baseUrl?: string
|
return (base ?? window.location.origin) + '/w/p/' + playlist.shortUUID
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildVideoLink (video: Pick<Video, 'shortUUID'>, base?: string) {
|
||||||
|
return (base ?? window.location.origin) + '/w/' + video.shortUUID
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPlaylistEmbedLink (playlist: Pick<VideoPlaylist, 'uuid'>, base?: string) {
|
||||||
|
return (base ?? window.location.origin) + '/video-playlists/embed/' + playlist.uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildVideoEmbedLink (video: Pick<Video, 'uuid'>, base?: string) {
|
||||||
|
return (base ?? window.location.origin) + '/videos/embed/' + video.uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
function decorateVideoLink (options: {
|
||||||
|
url: string
|
||||||
|
|
||||||
startTime?: number
|
startTime?: number
|
||||||
stopTime?: number
|
stopTime?: number
|
||||||
|
@ -60,12 +76,8 @@ function buildVideoLink (options: {
|
||||||
warningTitle?: boolean
|
warningTitle?: boolean
|
||||||
controls?: boolean
|
controls?: boolean
|
||||||
peertubeLink?: boolean
|
peertubeLink?: boolean
|
||||||
} = {}) {
|
}) {
|
||||||
const { baseUrl } = options
|
const { url } = options
|
||||||
|
|
||||||
const url = baseUrl
|
|
||||||
? baseUrl
|
|
||||||
: window.location.origin + window.location.pathname.replace('/embed/', '/w/')
|
|
||||||
|
|
||||||
const params = generateParams(window.location.search)
|
const params = generateParams(window.location.search)
|
||||||
|
|
||||||
|
@ -92,16 +104,12 @@ function buildVideoLink (options: {
|
||||||
return buildUrl(url, params)
|
return buildUrl(url, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildPlaylistLink (options: {
|
function decoratePlaylistLink (options: {
|
||||||
baseUrl?: string
|
url: string
|
||||||
|
|
||||||
playlistPosition?: number
|
playlistPosition?: number
|
||||||
}) {
|
}) {
|
||||||
const { baseUrl } = options
|
const { url } = options
|
||||||
|
|
||||||
const url = baseUrl
|
|
||||||
? baseUrl
|
|
||||||
: window.location.origin + window.location.pathname.replace('/video-playlists/embed/', '/w/p/')
|
|
||||||
|
|
||||||
const params = generateParams(window.location.search)
|
const params = generateParams(window.location.search)
|
||||||
|
|
||||||
|
@ -224,8 +232,14 @@ export {
|
||||||
timeToInt,
|
timeToInt,
|
||||||
secondsToTime,
|
secondsToTime,
|
||||||
isWebRTCDisabled,
|
isWebRTCDisabled,
|
||||||
|
|
||||||
buildPlaylistLink,
|
buildPlaylistLink,
|
||||||
buildVideoLink,
|
buildVideoLink,
|
||||||
|
decorateVideoLink,
|
||||||
|
decoratePlaylistLink,
|
||||||
|
buildPlaylistEmbedLink,
|
||||||
|
buildVideoEmbedLink,
|
||||||
|
|
||||||
buildVideoOrPlaylistEmbed,
|
buildVideoOrPlaylistEmbed,
|
||||||
videoFileMaxByResolution,
|
videoFileMaxByResolution,
|
||||||
videoFileMinByResolution,
|
videoFileMinByResolution,
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import { buildVideoLink } from '../utils'
|
|
||||||
import videojs from 'video.js'
|
import videojs from 'video.js'
|
||||||
|
import { PeerTubeLinkButtonOptions } from '../peertube-videojs-typings'
|
||||||
|
import { buildVideoLink, decorateVideoLink } from '../utils'
|
||||||
|
|
||||||
const Button = videojs.getComponent('Button')
|
const Button = videojs.getComponent('Button')
|
||||||
class PeerTubeLinkButton extends Button {
|
class PeerTubeLinkButton extends Button {
|
||||||
|
private shortUUID: string
|
||||||
|
|
||||||
constructor (player: videojs.Player, options?: videojs.ComponentOptions) {
|
constructor (player: videojs.Player, options?: PeerTubeLinkButtonOptions) {
|
||||||
super(player, options)
|
super(player, options as any)
|
||||||
}
|
}
|
||||||
|
|
||||||
createEl () {
|
createEl () {
|
||||||
|
@ -13,7 +15,7 @@ class PeerTubeLinkButton extends Button {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHref () {
|
updateHref () {
|
||||||
this.el().setAttribute('href', buildVideoLink({ startTime: this.player().currentTime() }))
|
this.el().setAttribute('href', this.buildLink())
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClick () {
|
handleClick () {
|
||||||
|
@ -22,7 +24,7 @@ class PeerTubeLinkButton extends Button {
|
||||||
|
|
||||||
private buildElement () {
|
private buildElement () {
|
||||||
const el = videojs.dom.createEl('a', {
|
const el = videojs.dom.createEl('a', {
|
||||||
href: buildVideoLink(),
|
href: this.buildLink(),
|
||||||
innerHTML: 'PeerTube',
|
innerHTML: 'PeerTube',
|
||||||
title: this.player().localize('Video page (new window)'),
|
title: this.player().localize('Video page (new window)'),
|
||||||
className: 'vjs-peertube-link',
|
className: 'vjs-peertube-link',
|
||||||
|
@ -33,6 +35,12 @@ class PeerTubeLinkButton extends Button {
|
||||||
|
|
||||||
return el as HTMLButtonElement
|
return el as HTMLButtonElement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private buildLink () {
|
||||||
|
const url = buildVideoLink({ shortUUID: this.shortUUID })
|
||||||
|
|
||||||
|
return decorateVideoLink({ url, startTime: this.player().currentTime() })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
videojs.registerComponent('PeerTubeLinkButton', PeerTubeLinkButton)
|
videojs.registerComponent('PeerTubeLinkButton', PeerTubeLinkButton)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export * from './date'
|
export * from './date'
|
||||||
export * from './miscs'
|
export * from './miscs'
|
||||||
export * from './types'
|
|
||||||
export * from './regexp'
|
export * from './regexp'
|
||||||
|
export * from './types'
|
||||||
|
export * from './url
|
0
shared/core-utils/common/url.ts
Normal file
0
shared/core-utils/common/url.ts
Normal file
|
@ -1,7 +1,7 @@
|
||||||
export * from './abuse'
|
export * from './abuse'
|
||||||
|
export * from './common'
|
||||||
export * from './i18n'
|
export * from './i18n'
|
||||||
export * from './logs'
|
export * from './logs'
|
||||||
export * from './miscs'
|
|
||||||
export * from './plugins'
|
export * from './plugins'
|
||||||
export * from './renderer'
|
export * from './renderer'
|
||||||
export * from './users'
|
export * from './users'
|
||||||
|
|
Loading…
Reference in a new issue