From cfc16a6db88378f83fa3a501170fa0fc5e7d6636 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 14 Sep 2018 14:36:12 +0200 Subject: Fix tag search on overview page --- client/src/app/videos/video-list/video-overview.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'client') diff --git a/client/src/app/videos/video-list/video-overview.component.html b/client/src/app/videos/video-list/video-overview.component.html index 4150cd5e1..4dad6a6e4 100644 --- a/client/src/app/videos/video-list/video-overview.component.html +++ b/client/src/app/videos/video-list/video-overview.component.html @@ -12,7 +12,7 @@
-- cgit v1.2.3 From 860cfb31e343f2317416da738f7155803ef4fe75 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 17 Sep 2018 10:28:38 +0200 Subject: Fix "no results" on overview page --- client/src/app/shared/overview/overview.service.ts | 2 ++ 1 file changed, 2 insertions(+) (limited to 'client') diff --git a/client/src/app/shared/overview/overview.service.ts b/client/src/app/shared/overview/overview.service.ts index 4a4714af6..097079e6d 100644 --- a/client/src/app/shared/overview/overview.service.ts +++ b/client/src/app/shared/overview/overview.service.ts @@ -56,6 +56,8 @@ export class OverviewService { } } + if (observables.length === 0) return of(videosOverviewResult) + return forkJoin(observables) .pipe( // Translate categories -- cgit v1.2.3 From b335ccec49b450052e3520f66f9acb6670e669f8 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 17 Sep 2018 15:00:46 +0200 Subject: Fix ios player playback/subtitles menu --- .../src/assets/player/peertube-videojs-plugin.ts | 201 +++++++++++---------- client/src/assets/player/settings-menu-item.ts | 7 +- client/src/sass/application.scss | 2 +- client/src/sass/player/index.scss | 5 + client/src/sass/player/peertube-skin.scss | 5 +- client/src/sass/player/player.scss | 5 - client/src/standalone/videos/embed.scss | 2 +- 7 files changed, 115 insertions(+), 112 deletions(-) create mode 100644 client/src/sass/player/index.scss delete mode 100644 client/src/sass/player/player.scss (limited to 'client') diff --git a/client/src/assets/player/peertube-videojs-plugin.ts b/client/src/assets/player/peertube-videojs-plugin.ts index 4b0677fab..36b80bd72 100644 --- a/client/src/assets/player/peertube-videojs-plugin.ts +++ b/client/src/assets/player/peertube-videojs-plugin.ts @@ -4,7 +4,7 @@ import { VideoFile } from '../../../../shared/models/videos/video.model' import { renderVideo } from './video-renderer' import './settings-menu-button' import { PeertubePluginOptions, VideoJSCaption, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' -import { isMobile, videoFileMaxByResolution, videoFileMinByResolution, timeToInt } from './utils' +import { isMobile, timeToInt, videoFileMaxByResolution, videoFileMinByResolution } from './utils' import * as CacheChunkStore from 'cache-chunk-store' import { PeertubeChunkStore } from './peertube-chunk-store' import { @@ -83,11 +83,6 @@ class PeerTubePlugin extends Plugin { this.videoCaptions = options.videoCaptions this.savePlayerSrcFunction = this.player.src - // Hack to "simulate" src link in video.js >= 6 - // Without this, we can't play the video after pausing it - // https://github.com/videojs/video.js/blob/master/src/js/player.js#L1633 - this.player.src = () => true - this.playerElement = options.playerElement if (this.autoplay === true) this.player.addClass('vjs-has-autoplay') @@ -104,9 +99,7 @@ class PeerTubePlugin extends Plugin { this.player.one('play', () => { // Don't run immediately scheduler, wait some seconds the TCP connections are made - this.runAutoQualitySchedulerTimer = setTimeout(() => { - this.runAutoQualityScheduler() - }, this.CONSTANTS.AUTO_QUALITY_SCHEDULER) + this.runAutoQualitySchedulerTimer = setTimeout(() => this.runAutoQualityScheduler(), this.CONSTANTS.AUTO_QUALITY_SCHEDULER) }) }) @@ -167,6 +160,9 @@ class PeerTubePlugin extends Plugin { // Do not display error to user because we will have multiple fallback this.disableErrorDisplay() + // Hack to "simulate" src link in video.js >= 6 + // Without this, we can't play the video after pausing it + // https://github.com/videojs/video.js/blob/master/src/js/player.js#L1633 this.player.src = () => true const oldPlaybackRate = this.player.playbackRate() @@ -181,7 +177,66 @@ class PeerTubePlugin extends Plugin { this.trigger('videoFileUpdate') } - addTorrent ( + updateResolution (resolutionId: number, delay = 0) { + // Remember player state + const currentTime = this.player.currentTime() + const isPaused = this.player.paused() + + // Remove poster to have black background + this.playerElement.poster = '' + + // Hide bigPlayButton + if (!isPaused) { + this.player.bigPlayButton.hide() + } + + const newVideoFile = this.videoFiles.find(f => f.resolution.id === resolutionId) + const options = { + forcePlay: false, + delay, + seek: currentTime + (delay / 1000) + } + this.updateVideoFile(newVideoFile, options) + } + + flushVideoFile (videoFile: VideoFile, destroyRenderer = true) { + if (videoFile !== undefined && this.webtorrent.get(videoFile.magnetUri)) { + if (destroyRenderer === true && this.renderer && this.renderer.destroy) this.renderer.destroy() + + this.webtorrent.remove(videoFile.magnetUri) + console.log('Removed ' + videoFile.magnetUri) + } + } + + isAutoResolutionOn () { + return this.autoResolution + } + + enableAutoResolution () { + this.autoResolution = true + this.trigger('autoResolutionUpdate') + } + + disableAutoResolution (forbid = false) { + if (forbid === true) this.forbidAutoResolution = true + + this.autoResolution = false + this.trigger('autoResolutionUpdate') + } + + isAutoResolutionForbidden () { + return this.forbidAutoResolution === true + } + + getCurrentVideoFile () { + return this.currentVideoFile + } + + getTorrent () { + return this.torrent + } + + private addTorrent ( magnetOrTorrentUrl: string, previousVideoFile: VideoFile, options: { @@ -205,26 +260,15 @@ class PeerTubePlugin extends Plugin { if (oldTorrent) { // Pause the old torrent - oldTorrent.pause() - // Pause does not remove actual peers (in particular the webseed peer) - oldTorrent.removePeer(oldTorrent['ws']) + this.stopTorrent(oldTorrent) // We use a fake renderer so we download correct pieces of the next file - if (options.delay) { - const fakeVideoElem = document.createElement('video') - renderVideo(torrent.files[0], fakeVideoElem, { autoplay: false, controls: false }, (err, renderer) => { - this.fakeRenderer = renderer - - if (err) console.error('Cannot render new torrent in fake video element.', err) - - // Load the future file at the correct time - fakeVideoElem.currentTime = this.player.currentTime() + (options.delay / 2000) - }) - } + if (options.delay) this.renderFileInFakeElement(torrent.files[ 0 ], options.delay) } // Render the video in a few seconds? (on resolution change for example, we wait some seconds of the new video resolution) this.addTorrentDelay = setTimeout(() => { + // We don't need the fake renderer anymore this.destroyFakeRenderer() const paused = this.player.paused() @@ -232,7 +276,7 @@ class PeerTubePlugin extends Plugin { this.flushVideoFile(previousVideoFile) const renderVideoOptions = { autoplay: false, controls: true } - renderVideo(torrent.files[0], this.playerElement, renderVideoOptions,(err, renderer) => { + renderVideo(torrent.files[ 0 ], this.playerElement, renderVideoOptions, (err, renderer) => { this.renderer = renderer if (err) return this.fallbackToHttp(done) @@ -265,7 +309,7 @@ class PeerTubePlugin extends Plugin { if (err.message.indexOf('incorrect info hash') !== -1) { console.error('Incorrect info hash detected, falling back to torrent file.') const newOptions = { forcePlay: true, seek: options.seek } - return this.addTorrent(this.torrent['xs'], previousVideoFile, newOptions, done) + return this.addTorrent(this.torrent[ 'xs' ], previousVideoFile, newOptions, done) } // Remote instance is down @@ -277,65 +321,6 @@ class PeerTubePlugin extends Plugin { }) } - updateResolution (resolutionId: number, delay = 0) { - // Remember player state - const currentTime = this.player.currentTime() - const isPaused = this.player.paused() - - // Remove poster to have black background - this.playerElement.poster = '' - - // Hide bigPlayButton - if (!isPaused) { - this.player.bigPlayButton.hide() - } - - const newVideoFile = this.videoFiles.find(f => f.resolution.id === resolutionId) - const options = { - forcePlay: false, - delay, - seek: currentTime + (delay / 1000) - } - this.updateVideoFile(newVideoFile, options) - } - - flushVideoFile (videoFile: VideoFile, destroyRenderer = true) { - if (videoFile !== undefined && this.webtorrent.get(videoFile.magnetUri)) { - if (destroyRenderer === true && this.renderer && this.renderer.destroy) this.renderer.destroy() - - this.webtorrent.remove(videoFile.magnetUri) - console.log('Removed ' + videoFile.magnetUri) - } - } - - isAutoResolutionOn () { - return this.autoResolution - } - - enableAutoResolution () { - this.autoResolution = true - this.trigger('autoResolutionUpdate') - } - - disableAutoResolution (forbid = false) { - if (forbid === true) this.forbidAutoResolution = true - - this.autoResolution = false - this.trigger('autoResolutionUpdate') - } - - isAutoResolutionForbidden () { - return this.forbidAutoResolution === true - } - - getCurrentVideoFile () { - return this.currentVideoFile - } - - getTorrent () { - return this.torrent - } - private tryToPlay (done?: Function) { if (!done) done = function () { /* empty */ } @@ -435,22 +420,22 @@ class PeerTubePlugin extends Plugin { if (this.autoplay === true) { this.player.posterImage.hide() - this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime }) - } else { - // Don't try on iOS that does not support MediaSource - if (this.isIOS()) { - this.currentVideoFile = this.pickAverageVideoFile() - return this.fallbackToHttp(undefined, false) - } + return this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime }) + } - // Proxy first play - const oldPlay = this.player.play.bind(this.player) - this.player.play = () => { - this.player.addClass('vjs-has-big-play-button-clicked') - this.player.play = oldPlay + // Don't try on iOS that does not support MediaSource + if (this.isIOS()) { + this.currentVideoFile = this.pickAverageVideoFile() + return this.fallbackToHttp(undefined, false) + } - this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime }) - } + // Proxy first play + const oldPlay = this.player.play.bind(this.player) + this.player.play = () => { + this.player.addClass('vjs-has-big-play-button-clicked') + this.player.play = oldPlay + + this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime }) } } @@ -607,6 +592,24 @@ class PeerTubePlugin extends Plugin { return this.videoFiles[Math.floor(this.videoFiles.length / 2)] } + private stopTorrent (torrent: WebTorrent.Torrent) { + torrent.pause() + // Pause does not remove actual peers (in particular the webseed peer) + torrent.removePeer(torrent[ 'ws' ]) + } + + private renderFileInFakeElement (file: WebTorrent.TorrentFile, delay: number) { + const fakeVideoElem = document.createElement('video') + renderVideo(file, fakeVideoElem, { autoplay: false, controls: false }, (err, renderer) => { + this.fakeRenderer = renderer + + if (err) console.error('Cannot render new torrent in fake video element.', err) + + // Load the future file at the correct time (in delay MS - 2 seconds) + fakeVideoElem.currentTime = this.player.currentTime() + (delay - 2000) + }) + } + private destroyFakeRenderer () { if (this.fakeRenderer) { if (this.fakeRenderer.destroy) { diff --git a/client/src/assets/player/settings-menu-item.ts b/client/src/assets/player/settings-menu-item.ts index 6e2224e20..f6cf6d0f3 100644 --- a/client/src/assets/player/settings-menu-item.ts +++ b/client/src/assets/player/settings-menu-item.ts @@ -38,8 +38,11 @@ class SettingsMenuItem extends MenuItem { this.eventHandlers() player.ready(() => { - this.build() - this.reset() + // Voodoo magic for IOS + setTimeout(() => { + this.build() + this.reset() + }, 0) }) } diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss index 8d2bfb077..c1135cd02 100644 --- a/client/src/sass/application.scss +++ b/client/src/sass/application.scss @@ -9,7 +9,7 @@ $icon-font-path: '../../node_modules/@neos21/bootstrap3-glyphicons/assets/fonts/ @import '~video.js/dist/video-js.css'; $assets-path: '../assets/'; -@import './player/player'; +@import './player/index'; @import './loading-bar'; @import './primeng-custom'; diff --git a/client/src/sass/player/index.scss b/client/src/sass/player/index.scss new file mode 100644 index 000000000..e4a315d1f --- /dev/null +++ b/client/src/sass/player/index.scss @@ -0,0 +1,5 @@ +@import './peertube-skin'; +@import './mobile'; +@import './context-menu'; +@import './settings-menu'; +@import './spinner'; \ No newline at end of file diff --git a/client/src/sass/player/peertube-skin.scss b/client/src/sass/player/peertube-skin.scss index 185b00222..4e921e970 100644 --- a/client/src/sass/player/peertube-skin.scss +++ b/client/src/sass/player/peertube-skin.scss @@ -406,6 +406,7 @@ width: 37px; margin-right: 1px; + cursor: pointer; .vjs-icon-placeholder { transition: transform 0.2s ease; @@ -504,10 +505,6 @@ } } - .vjs-playback-rate { - display: none; - } - .vjs-peertube { padding: 0 !important; diff --git a/client/src/sass/player/player.scss b/client/src/sass/player/player.scss deleted file mode 100644 index e4a315d1f..000000000 --- a/client/src/sass/player/player.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import './peertube-skin'; -@import './mobile'; -@import './context-menu'; -@import './settings-menu'; -@import './spinner'; \ No newline at end of file diff --git a/client/src/standalone/videos/embed.scss b/client/src/standalone/videos/embed.scss index 30650538f..c40ea1208 100644 --- a/client/src/standalone/videos/embed.scss +++ b/client/src/standalone/videos/embed.scss @@ -4,7 +4,7 @@ @import '~videojs-dock/dist/videojs-dock.css'; $assets-path: '../../assets/'; -@import '../../sass/player/player'; +@import '../../sass/player/index'; [hidden] { display: none !important; -- cgit v1.2.3 From e452d2e2b80b2fbea88a1fe9c40b49e8241eae92 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 17 Sep 2018 15:28:32 +0200 Subject: Fix description/comments max width --- client/src/app/videos/+video-watch/video-watch.component.scss | 1 + 1 file changed, 1 insertion(+) (limited to 'client') diff --git a/client/src/app/videos/+video-watch/video-watch.component.scss b/client/src/app/videos/+video-watch/video-watch.component.scss index fac4bdbe5..15adf0f61 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.scss +++ b/client/src/app/videos/+video-watch/video-watch.component.scss @@ -81,6 +81,7 @@ flex-grow: 1; // Set min width for flex item min-width: 1px; + max-width: 100%; .video-info-first-row { display: flex; -- cgit v1.2.3 From 8c72543a4af7a613496e0581a939996fc284f861 Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Mon, 17 Sep 2018 16:44:41 +0200 Subject: adding missing i18n for schedule option --- .../videos/+video-edit/video-add-components/video-upload.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'client') diff --git a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html index 8c0723155..ff0e45413 100644 --- a/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html +++ b/client/src/app/videos/+video-edit/video-add-components/video-upload.component.html @@ -22,7 +22,7 @@
-- cgit v1.2.3 From a8ecc6f6709bdb54c47c7dd7cd18ef371254c3af Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 17 Sep 2018 17:36:46 +0200 Subject: Try to improve infinite pagination --- .../src/app/shared/video/abstract-video-list.html | 2 +- client/src/app/shared/video/abstract-video-list.ts | 29 +++++++++++++++++++--- .../shared/video/infinite-scroller.directive.ts | 13 +++++++--- 3 files changed, 37 insertions(+), 7 deletions(-) (limited to 'client') diff --git a/client/src/app/shared/video/abstract-video-list.html b/client/src/app/shared/video/abstract-video-list.html index 0f48b9a64..4ad4e3568 100644 --- a/client/src/app/shared/video/abstract-video-list.html +++ b/client/src/app/shared/video/abstract-video-list.html @@ -7,7 +7,7 @@
No results.
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts index b8fd7f8eb..9df4cfc22 100644 --- a/client/src/app/shared/video/abstract-video-list.ts +++ b/client/src/app/shared/video/abstract-video-list.ts @@ -38,7 +38,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { ownerDisplayType: OwnerDisplayType = 'account' protected baseVideoWidth = 215 - protected baseVideoHeight = 230 + protected baseVideoHeight = 205 protected abstract notificationsService: NotificationsService protected abstract authService: AuthService @@ -55,6 +55,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { protected otherRouteParams = {} private resizeSubscription: Subscription + private firstLoadedPage: number abstract getVideosObservable (page: number): Observable<{ videos: Video[], totalVideos: number}> abstract generateSyndicationList () @@ -100,7 +101,11 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { this.loadMoreVideos(this.pagination.currentPage) } - loadMoreVideos (page: number) { + loadMoreVideos (page: number, loadOnTop = false) { + this.adjustVideoPageHeight() + + const currentY = window.scrollY + if (this.loadedPages[page] !== undefined) return if (this.loadingPage[page] === true) return @@ -111,6 +116,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { ({ videos, totalVideos }) => { this.loadingPage[page] = false + if (this.firstLoadedPage === undefined || this.firstLoadedPage > page) this.firstLoadedPage = page + // Paging is too high, return to the first one if (this.pagination.currentPage > 1 && totalVideos <= ((this.pagination.currentPage - 1) * this.pagination.itemsPerPage)) { this.pagination.currentPage = 1 @@ -125,8 +132,17 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { // Initialize infinite scroller now we loaded the first page if (Object.keys(this.loadedPages).length === 1) { // Wait elements creation - setTimeout(() => this.infiniteScroller.initialize(), 500) + setTimeout(() => { + this.infiniteScroller.initialize() + + // At our first load, we did not load the first page + // Load the previous page so the user can move on the top (and browser previous pages) + if (this.pagination.currentPage > 1) this.loadMoreVideos(this.pagination.currentPage - 1, true) + }, 500) } + + // Insert elements on the top but keep the scroll in the previous position + if (loadOnTop) setTimeout(() => { window.scrollTo(0, currentY + this.pageHeight) }, 0) }, error => { this.loadingPage[page] = false @@ -189,6 +205,13 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { this.videoPages = Object.values(this.loadedPages) } + protected adjustVideoPageHeight () { + const numberOfPagesLoaded = Object.keys(this.loadedPages).length + if (!numberOfPagesLoaded) return + + this.pageHeight = this.videosElement.nativeElement.offsetHeight / numberOfPagesLoaded + } + protected buildVideoHeight () { // Same ratios than base width/height return this.videosElement.nativeElement.offsetWidth * (this.baseVideoHeight / this.baseVideoWidth) diff --git a/client/src/app/shared/video/infinite-scroller.directive.ts b/client/src/app/shared/video/infinite-scroller.directive.ts index 4dc1f86e7..a02e9444a 100644 --- a/client/src/app/shared/video/infinite-scroller.directive.ts +++ b/client/src/app/shared/video/infinite-scroller.directive.ts @@ -6,10 +6,9 @@ import { fromEvent, Subscription } from 'rxjs' selector: '[myInfiniteScroller]' }) export class InfiniteScrollerDirective implements OnInit, OnDestroy { - private static PAGE_VIEW_TOP_MARGIN = 500 - @Input() containerHeight: number @Input() pageHeight: number + @Input() firstLoadedPage = 1 @Input() percentLimit = 70 @Input() autoInit = false @@ -23,6 +22,7 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy { private scrollDownSub: Subscription private scrollUpSub: Subscription private pageChangeSub: Subscription + private middleScreen: number constructor () { this.decimalLimit = this.percentLimit / 100 @@ -39,6 +39,8 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy { } initialize () { + this.middleScreen = window.innerHeight / 2 + // Emit the last value const throttleOptions = { leading: true, trailing: true } @@ -92,6 +94,11 @@ export class InfiniteScrollerDirective implements OnInit, OnDestroy { } private calculateCurrentPage (current: number) { - return Math.max(1, Math.round((current + InfiniteScrollerDirective.PAGE_VIEW_TOP_MARGIN) / this.pageHeight)) + const scrollY = current + this.middleScreen + + const page = Math.max(1, Math.ceil(scrollY / this.pageHeight)) + + // Offset page + return page + (this.firstLoadedPage - 1) } } -- cgit v1.2.3 From d5931e623320d0851a19e1001e90c7d8138d7a20 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 18 Sep 2018 08:21:04 +0200 Subject: Fix client build --- client/src/app/shared/video/abstract-video-list.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'client') diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts index 9df4cfc22..53b044478 100644 --- a/client/src/app/shared/video/abstract-video-list.ts +++ b/client/src/app/shared/video/abstract-video-list.ts @@ -36,6 +36,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { videoHeight: number videoPages: Video[][] = [] ownerDisplayType: OwnerDisplayType = 'account' + firstLoadedPage: number protected baseVideoWidth = 215 protected baseVideoHeight = 205 @@ -55,7 +56,6 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { protected otherRouteParams = {} private resizeSubscription: Subscription - private firstLoadedPage: number abstract getVideosObservable (page: number): Observable<{ videos: Video[], totalVideos: number}> abstract generateSyndicationList () -- cgit v1.2.3 From e972e046dbe9b499944c4fab9220eee13e31ac1b Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 18 Sep 2018 11:59:05 +0200 Subject: Don't get recommended videos twice --- .../src/app/videos/+video-watch/video-watch.component.ts | 2 +- .../recent-videos-recommendation.service.ts | 4 ++-- .../app/videos/recommendations/recommended-videos.store.ts | 14 +++++++++----- 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'client') 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 834428fa4..7a61e355a 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts @@ -1,4 +1,4 @@ -import { catchError, subscribeOn } from 'rxjs/operators' +import { catchError } from 'rxjs/operators' import { ChangeDetectorRef, Component, ElementRef, Inject, LOCALE_ID, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core' import { ActivatedRoute, Router } from '@angular/router' import { RedirectService } from '@app/core/routing/redirect.service' diff --git a/client/src/app/videos/recommendations/recent-videos-recommendation.service.ts b/client/src/app/videos/recommendations/recent-videos-recommendation.service.ts index 4723f7fd0..0ee34b9cb 100644 --- a/client/src/app/videos/recommendations/recent-videos-recommendation.service.ts +++ b/client/src/app/videos/recommendations/recent-videos-recommendation.service.ts @@ -25,8 +25,8 @@ export class RecentVideosRecommendationService implements RecommendationService getRecommendations (recommendation: RecommendationInfo): Observable { return this.fetchPage(1, recommendation) .pipe( - map(vids => { - const otherVideos = vids.filter(v => v.uuid !== recommendation.uuid) + map(videos => { + const otherVideos = videos.filter(v => v.uuid !== recommendation.uuid) return otherVideos.slice(0, this.pageSize) }) ) diff --git a/client/src/app/videos/recommendations/recommended-videos.store.ts b/client/src/app/videos/recommendations/recommended-videos.store.ts index eb5c9867f..858ec3a27 100644 --- a/client/src/app/videos/recommendations/recommended-videos.store.ts +++ b/client/src/app/videos/recommendations/recommended-videos.store.ts @@ -3,8 +3,8 @@ import { Observable, ReplaySubject } from 'rxjs' import { Video } from '@app/shared/video/video.model' import { RecommendationInfo } from '@app/shared/video/recommendation-info.model' import { RecentVideosRecommendationService } from '@app/videos/recommendations/recent-videos-recommendation.service' -import { RecommendationService, UUID } from '@app/videos/recommendations/recommendations.service' -import { map, switchMap, take } from 'rxjs/operators' +import { RecommendationService } from '@app/videos/recommendations/recommendations.service' +import { map, shareReplay, switchMap, take } from 'rxjs/operators' /** * This store is intended to provide data for the RecommendedVideosComponent. @@ -19,9 +19,13 @@ export class RecommendedVideosStore { @Inject(RecentVideosRecommendationService) private recommendations: RecommendationService ) { this.recommendations$ = this.requestsForLoad$$.pipe( - switchMap(requestedRecommendation => recommendations.getRecommendations(requestedRecommendation) - .pipe(take(1)) - )) + switchMap(requestedRecommendation => { + return recommendations.getRecommendations(requestedRecommendation) + .pipe(take(1)) + }), + shareReplay() + ) + this.hasRecommendations$ = this.recommendations$.pipe( map(otherVideos => otherVideos.length > 0) ) -- cgit v1.2.3 From ad76628b17ff8f25d3402d6d669b274116bbf76c Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 19 Sep 2018 09:53:49 +0200 Subject: Fix admin access to moderators --- client/src/app/+admin/moderation/moderation.routes.ts | 10 ++++++++++ client/src/app/menu/menu.component.ts | 10 +++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'client') diff --git a/client/src/app/+admin/moderation/moderation.routes.ts b/client/src/app/+admin/moderation/moderation.routes.ts index b133152d9..6d81b9b36 100644 --- a/client/src/app/+admin/moderation/moderation.routes.ts +++ b/client/src/app/+admin/moderation/moderation.routes.ts @@ -15,6 +15,16 @@ export const ModerationRoutes: Routes = [ redirectTo: 'video-abuses/list', pathMatch: 'full' }, + { + path: 'video-abuses', + redirectTo: 'video-abuses/list', + pathMatch: 'full' + }, + { + path: 'video-blacklist', + redirectTo: 'video-blacklist/list', + pathMatch: 'full' + }, { path: 'video-abuses/list', component: VideoAbuseListComponent, diff --git a/client/src/app/menu/menu.component.ts b/client/src/app/menu/menu.component.ts index 24cd5aa28..f13ecc2c7 100644 --- a/client/src/app/menu/menu.component.ts +++ b/client/src/app/menu/menu.component.ts @@ -19,8 +19,10 @@ export class MenuComponent implements OnInit { private routesPerRight = { [UserRight.MANAGE_USERS]: '/admin/users', [UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends', - [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/video-abuses', - [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/video-blacklist' + [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/moderation/video-abuses', + [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/moderation/video-blacklist', + [UserRight.MANAGE_JOBS]: '/admin/jobs', + [UserRight.MANAGE_CONFIGURATION]: '/admin/config' } constructor ( @@ -67,7 +69,9 @@ export class MenuComponent implements OnInit { UserRight.MANAGE_USERS, UserRight.MANAGE_SERVER_FOLLOW, UserRight.MANAGE_VIDEO_ABUSES, - UserRight.MANAGE_VIDEO_BLACKLIST + UserRight.MANAGE_VIDEO_BLACKLIST, + UserRight.MANAGE_JOBS, + UserRight.MANAGE_CONFIGURATION ] for (const adminRight of adminRights) { -- cgit v1.2.3 From fcc7c060374c3a547257d96af847352c14d6144b Mon Sep 17 00:00:00 2001 From: BO41 Date: Wed, 19 Sep 2018 18:27:10 +0200 Subject: rename manifest --- client/angular.json | 4 ++-- client/src/index.html | 2 +- client/src/manifest.json | 47 ----------------------------------------- client/src/manifest.webmanifest | 47 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 50 deletions(-) delete mode 100644 client/src/manifest.json create mode 100644 client/src/manifest.webmanifest (limited to 'client') diff --git a/client/angular.json b/client/angular.json index 789eeb3d0..2cf2ecd62 100644 --- a/client/angular.json +++ b/client/angular.json @@ -24,7 +24,7 @@ }, "assets": [ "src/assets/images", - "src/manifest.json" + "src/manifest.webmanifest" ], "styles": [ "src/sass/application.scss" @@ -105,7 +105,7 @@ ], "assets": [ "src/assets/images", - "src/manifest.json" + "src/manifest.webmanifest" ] } }, diff --git a/client/src/index.html b/client/src/index.html index f00af8bff..593de4ac6 100644 --- a/client/src/index.html +++ b/client/src/index.html @@ -7,7 +7,7 @@ - + diff --git a/client/src/manifest.json b/client/src/manifest.json deleted file mode 100644 index 30914e35f..000000000 --- a/client/src/manifest.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "background_color": "#fff", - "theme_color": "#fff", - "description": "A federated video streaming platform using P2P", - "display": "standalone", - "orientation": "any", - "icons": [ - { - "src": "/client/assets/images/icons/icon-36x36.png", - "sizes": "36x36", - "type": "image/png" - }, - { - "src": "/client/assets/images/icons/icon-48x48.png", - "sizes": "48x48", - "type": "image/png" - }, - { - "src": "/client/assets/images/icons/icon-72x72.png", - "sizes": "72x72", - "type": "image/png" - }, - { - "src": "/client/assets/images/icons/icon-96x96.png", - "sizes": "96x96", - "type": "image/png" - }, - { - "src": "/client/assets/images/icons/icon-144x144.png", - "sizes": "144x144", - "type": "image/png" - }, - { - "src": "/client/assets/images/icons/icon-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/client/assets/images/icons/icon-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "name": "PeerTube", - "short_name": "PeerTube", - "start_url": "/videos/trending" -} diff --git a/client/src/manifest.webmanifest b/client/src/manifest.webmanifest new file mode 100644 index 000000000..3d3c7d6d5 --- /dev/null +++ b/client/src/manifest.webmanifest @@ -0,0 +1,47 @@ +{ + "background_color": "#fff", + "theme_color": "#fff", + "description": "A federated video streaming platform using P2P", + "display": "standalone", + "orientation": "any", + "icons": [ + { + "src": "/client/assets/images/icons/icon-36x36.png", + "sizes": "36x36", + "type": "image/png" + }, + { + "src": "/client/assets/images/icons/icon-48x48.png", + "sizes": "48x48", + "type": "image/png" + }, + { + "src": "/client/assets/images/icons/icon-72x72.png", + "sizes": "72x72", + "type": "image/png" + }, + { + "src": "/client/assets/images/icons/icon-96x96.png", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "/client/assets/images/icons/icon-144x144.png", + "sizes": "144x144", + "type": "image/png" + }, + { + "src": "/client/assets/images/icons/icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/client/assets/images/icons/icon-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "name": "PeerTube", + "short_name": "PeerTube", + "start_url": "/videos/trending" +} -- cgit v1.2.3 From d466dece0a07555b91f01fa35fcc5dcfe79d9e12 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 20 Sep 2018 11:55:00 +0200 Subject: Improve message when removing a user --- client/src/app/+admin/users/user-list/user-list.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'client') diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts index 57e63d465..9697ce202 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/users/user-list/user-list.component.ts @@ -105,7 +105,8 @@ export class UserListComponent extends RestTable implements OnInit { return } - const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this user?'), this.i18n('Delete')) + const message = this.i18n('If you remove this user, you will not be able to create another with the same username!') + const res = await this.confirmService.confirm(message, this.i18n('Delete')) if (res === false) return this.userService.removeUser(user).subscribe( -- cgit v1.2.3 From 89724816ae79e0c4f9fba6f47267711f505ec7af Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 20 Sep 2018 14:21:57 +0200 Subject: Improve videos list client performance --- client/src/app/shared/video/abstract-video-list.html | 4 ++-- client/src/app/shared/video/abstract-video-list.ts | 11 ++++++++++- client/src/app/shared/video/video-miniature.component.html | 4 ++-- client/src/app/shared/video/video-miniature.component.ts | 11 ++++++----- client/src/hmr.ts | 10 +++++++++- 5 files changed, 29 insertions(+), 11 deletions(-) (limited to 'client') diff --git a/client/src/app/shared/video/abstract-video-list.html b/client/src/app/shared/video/abstract-video-list.html index 4ad4e3568..d543ab7c1 100644 --- a/client/src/app/shared/video/abstract-video-list.html +++ b/client/src/app/shared/video/abstract-video-list.html @@ -11,8 +11,8 @@ (nearOfTop)="onNearOfTop()" (nearOfBottom)="onNearOfBottom()" (pageChanged)="onPageChanged($event)" class="videos" #videosElement > -
- +
+
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts index 53b044478..6a758ebe0 100644 --- a/client/src/app/shared/video/abstract-video-list.ts +++ b/client/src/app/shared/video/abstract-video-list.ts @@ -81,6 +81,15 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { if (this.resizeSubscription) this.resizeSubscription.unsubscribe() } + pageByVideoId (index: number, page: Video[]) { + // Video are unique in all pages + return page[0].id + } + + videoById (index: number, video: Video) { + return video.id + } + onNearOfTop () { this.previousPage() } @@ -166,7 +175,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy { const min = this.minPageLoaded() if (min > 1) { - this.loadMoreVideos(min - 1) + this.loadMoreVideos(min - 1, true) } } diff --git a/client/src/app/shared/video/video-miniature.component.html b/client/src/app/shared/video/video-miniature.component.html index 9cf3fb321..cfc483018 100644 --- a/client/src/app/shared/video/video-miniature.component.html +++ b/client/src/app/shared/video/video-miniature.component.html @@ -1,11 +1,11 @@
- +
{{ video.name }} diff --git a/client/src/app/shared/video/video-miniature.component.ts b/client/src/app/shared/video/video-miniature.component.ts index 07193ebd5..27098f4b4 100644 --- a/client/src/app/shared/video/video-miniature.component.ts +++ b/client/src/app/shared/video/video-miniature.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core' +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core' import { User } from '../users' import { Video } from './video.model' import { ServerService } from '@app/core' @@ -8,13 +8,16 @@ export type OwnerDisplayType = 'account' | 'videoChannel' | 'auto' @Component({ selector: 'my-video-miniature', styleUrls: [ './video-miniature.component.scss' ], - templateUrl: './video-miniature.component.html' + templateUrl: './video-miniature.component.html', + changeDetection: ChangeDetectionStrategy.OnPush }) export class VideoMiniatureComponent implements OnInit { @Input() user: User @Input() video: Video @Input() ownerDisplayType: OwnerDisplayType = 'account' + isVideoBlur: boolean + private ownerDisplayTypeChosen: 'account' | 'videoChannel' constructor (private serverService: ServerService) { } @@ -35,10 +38,8 @@ export class VideoMiniatureComponent implements OnInit { } else { this.ownerDisplayTypeChosen = 'videoChannel' } - } - isVideoBlur () { - return this.video.isVideoNSFWForUser(this.user, this.serverService.getConfig()) + this.isVideoBlur = this.video.isVideoNSFWForUser(this.user, this.serverService.getConfig()) } displayOwnerAccount () { diff --git a/client/src/hmr.ts b/client/src/hmr.ts index 4d707a250..d5306a7a2 100644 --- a/client/src/hmr.ts +++ b/client/src/hmr.ts @@ -1,11 +1,19 @@ import { NgModuleRef, ApplicationRef } from '@angular/core' import { createNewHosts } from '@angularclass/hmr' +import { enableDebugTools } from '@angular/platform-browser' export const hmrBootstrap = (module: any, bootstrap: () => Promise>) => { let ngModule: NgModuleRef module.hot.accept() bootstrap() - .then(mod => ngModule = mod) + .then(mod => { + ngModule = mod + + const applicationRef = ngModule.injector.get(ApplicationRef); + const componentRef = applicationRef.components[ 0 ] + // allows to run `ng.profiler.timeChangeDetection();` + enableDebugTools(componentRef) + }) module.hot.dispose(() => { const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef) const elements = appRef.components.map(c => c.location.nativeElement) -- cgit v1.2.3 From 93ea9c47d989e28405cf1039f89be71e592e36a5 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 20 Sep 2018 14:49:12 +0200 Subject: Improve responsive on small screens --- .../comment/video-comment-add.component.scss | 6 +++++ .../comment/video-comment.component.scss | 7 ++++++ .../comment/video-comments.component.scss | 8 ++++++- .../videos/+video-watch/video-watch.component.scss | 27 ++++++++++++++++++++-- client/src/sass/include/_mixins.scss | 1 - 5 files changed, 45 insertions(+), 4 deletions(-) (limited to 'client') diff --git a/client/src/app/videos/+video-watch/comment/video-comment-add.component.scss b/client/src/app/videos/+video-watch/comment/video-comment-add.component.scss index a55e743fb..bb809296a 100644 --- a/client/src/app/videos/+video-watch/comment/video-comment-add.component.scss +++ b/client/src/app/videos/+video-watch/comment/video-comment-add.component.scss @@ -39,3 +39,9 @@ form { @include orange-button } } + +@media screen and (max-width: 450px) { + textarea, .submit-comment button { + font-size: 14px !important; + } +} \ No newline at end of file diff --git a/client/src/app/videos/+video-watch/comment/video-comment.component.scss b/client/src/app/videos/+video-watch/comment/video-comment.component.scss index f331fab80..84da5727e 100644 --- a/client/src/app/videos/+video-watch/comment/video-comment.component.scss +++ b/client/src/app/videos/+video-watch/comment/video-comment.component.scss @@ -35,6 +35,7 @@ .comment-account { @include disable-default-a-behaviour; + word-break: break-all; color: var(--mainForegroundColor); font-weight: $font-bold; } @@ -102,3 +103,9 @@ img { margin-right: 10px; } } } + +@media screen and (max-width: 450px) { + .root-comment { + font-size: 14px; + } +} \ No newline at end of file diff --git a/client/src/app/videos/+video-watch/comment/video-comments.component.scss b/client/src/app/videos/+video-watch/comment/video-comments.component.scss index d5af929d7..04518e079 100644 --- a/client/src/app/videos/+video-watch/comment/video-comments.component.scss +++ b/client/src/app/videos/+video-watch/comment/video-comments.component.scss @@ -31,4 +31,10 @@ my-help { .view-replies { margin-left: 46px; } -} \ No newline at end of file +} + +@media screen and (max-width: 450px) { + .view-replies { + font-size: 14px; + } +} diff --git a/client/src/app/videos/+video-watch/video-watch.component.scss b/client/src/app/videos/+video-watch/video-watch.component.scss index 15adf0f61..eb63cbde7 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.scss +++ b/client/src/app/videos/+video-watch/video-watch.component.scss @@ -473,6 +473,7 @@ my-video-comments { margin: 20px 0 0 0; .video-info { + padding: 0; .video-info-first-row { @@ -485,6 +486,8 @@ my-video-comments { } /deep/ .other-videos { + padding-left: 0 !important; + /deep/ .video-miniature { flex-direction: column; } @@ -500,7 +503,27 @@ my-video-comments { } @media screen and (max-width: 450px) { - .video-bottom .action-button .icon-text { - display: none !important; + .video-bottom { + .action-button .icon-text { + display: none !important; + } + + .video-info .video-info-first-row { + .video-info-name { + font-size: 18px; + } + + .video-info-date-views { + font-size: 14px; + } + + .video-actions-rates { + margin-top: 10px; + } + } + + .video-info-description { + font-size: 14px !important; + } } } diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss index d755e7df3..544f39957 100644 --- a/client/src/sass/include/_mixins.scss +++ b/client/src/sass/include/_mixins.scss @@ -53,7 +53,6 @@ -ms-hyphens: auto; -moz-hyphens: auto; hyphens: auto; - text-align: justify; } @mixin peertube-input-text($width) { -- cgit v1.2.3 From 6247b2057b792cea155a1abd9788c363ae7d2cc2 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 20 Sep 2018 15:45:11 +0200 Subject: Fix client e2e tests --- client/e2e/src/po/video-watch.po.ts | 7 +++++-- client/e2e/src/videos.e2e-spec.ts | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'client') diff --git a/client/e2e/src/po/video-watch.po.ts b/client/e2e/src/po/video-watch.po.ts index 13f4ae945..e17aebc29 100644 --- a/client/e2e/src/po/video-watch.po.ts +++ b/client/e2e/src/po/video-watch.po.ts @@ -26,8 +26,11 @@ export class VideoWatchPage { .then((texts: any) => texts.map(t => t.trim())) } - waitWatchVideoName (videoName: string, isSafari: boolean) { - const elem = element(by.css('.video-info .video-info-name')) + waitWatchVideoName (videoName: string, isMobileDevice: boolean, isSafari: boolean) { + // On mobile we display the first node, on desktop the second + const index = isMobileDevice ? 0 : 1 + + const elem = element.all(by.css('.video-info .video-info-name')).get(index) if (isSafari) return browser.sleep(5000) diff --git a/client/e2e/src/videos.e2e-spec.ts b/client/e2e/src/videos.e2e-spec.ts index 3d4d46292..606b6ac5d 100644 --- a/client/e2e/src/videos.e2e-spec.ts +++ b/client/e2e/src/videos.e2e-spec.ts @@ -12,7 +12,7 @@ describe('Videos workflow', () => { let isSafari = false beforeEach(async () => { - browser.waitForAngularEnabled(false) + await browser.waitForAngularEnabled(false) videoWatchPage = new VideoWatchPage() pageUploadPage = new VideoUploadPage() @@ -62,7 +62,7 @@ describe('Videos workflow', () => { if (isMobileDevice || isSafari) videoNameToExcept = await videoWatchPage.clickOnFirstVideo() else await videoWatchPage.clickOnVideo(videoName) - return videoWatchPage.waitWatchVideoName(videoNameToExcept, isSafari) + return videoWatchPage.waitWatchVideoName(videoNameToExcept, isMobileDevice, isSafari) }) it('Should play the video', async () => { -- cgit v1.2.3