From: Rigel Kent Date: Wed, 11 Dec 2019 21:13:20 +0000 (+0100) Subject: add loop setting for playlists, and use sessionStorage X-Git-Tag: v2.1.0-rc.1~213 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=88a7f93f8e5666f44121a2e3cf9d33d74c472aa7;p=oweals%2Fpeertube.git add loop setting for playlists, and use sessionStorage --- diff --git a/client/src/app/+admin/system/jobs/jobs.component.ts b/client/src/app/+admin/system/jobs/jobs.component.ts index 95ee17023..c3211d71f 100644 --- a/client/src/app/+admin/system/jobs/jobs.component.ts +++ b/client/src/app/+admin/system/jobs/jobs.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core' -import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' +import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage' import { Notifier } from '@app/core' import { SortMeta } from 'primeng/api' import { Job, JobType } from '../../../../../../shared/index' diff --git a/client/src/app/core/auth/auth-user.model.ts b/client/src/app/core/auth/auth-user.model.ts index 334ede0cd..d371a923f 100644 --- a/client/src/app/core/auth/auth-user.model.ts +++ b/client/src/app/core/auth/auth-user.model.ts @@ -1,4 +1,4 @@ -import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' +import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage' import { UserRight } from '../../../../../shared/models/users/user-right.enum' import { User as ServerUserModel } from '../../../../../shared/models/users/user.model' // Do not use the barrel (dependency loop) diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts index eaa822e0f..d601cadf5 100644 --- a/client/src/app/core/auth/auth.service.ts +++ b/client/src/app/core/auth/auth.service.ts @@ -12,7 +12,7 @@ import { RestExtractor } from '../../shared/rest/rest-extractor.service' import { AuthStatus } from './auth-status.model' import { AuthUser } from './auth-user.model' import { objectToUrlEncoded } from '@app/shared/misc/utils' -import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' +import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage' import { I18n } from '@ngx-translate/i18n-polyfill' import { Hotkey, HotkeysService } from 'angular2-hotkeys' diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index 8e76bebb1..cf9c411a4 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts @@ -1,7 +1,7 @@ import { map, shareReplay, switchMap, tap } from 'rxjs/operators' import { HttpClient } from '@angular/common/http' import { Inject, Injectable, LOCALE_ID } from '@angular/core' -import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' +import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage' import { Observable, of, ReplaySubject } from 'rxjs' import { getCompleteLocale, ServerConfig } from '../../../../../shared' import { environment } from '../../../environments/environment' diff --git a/client/src/app/core/theme/theme.service.ts b/client/src/app/core/theme/theme.service.ts index b312e8f7a..9be8e7a2d 100644 --- a/client/src/app/core/theme/theme.service.ts +++ b/client/src/app/core/theme/theme.service.ts @@ -4,7 +4,7 @@ import { ServerService } from '@app/core/server' import { environment } from '../../../environments/environment' import { PluginService } from '@app/core/plugins/plugin.service' import { ServerConfigTheme } from '@shared/models' -import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' +import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage' @Injectable() export class ThemeService { diff --git a/client/src/app/shared/images/global-icon.component.ts b/client/src/app/shared/images/global-icon.component.ts index eb723db94..31cfe2666 100644 --- a/client/src/app/shared/images/global-icon.component.ts +++ b/client/src/app/shared/images/global-icon.component.ts @@ -26,6 +26,7 @@ const icons = { 'cross': require('!!raw-loader?!../../../assets/images/global/cross.svg'), 'validate': require('!!raw-loader?!../../../assets/images/global/validate.svg'), 'tick': require('!!raw-loader?!../../../assets/images/global/tick.svg'), + 'repeat': require('!!raw-loader?!../../../assets/images/global/repeat.svg'), 'dislike': require('!!raw-loader?!../../../assets/images/video/dislike.svg'), 'support': require('!!raw-loader?!../../../assets/images/video/support.svg'), 'like': require('!!raw-loader?!../../../assets/images/video/like.svg'), diff --git a/client/src/app/shared/misc/peertube-local-storage.ts b/client/src/app/shared/misc/peertube-local-storage.ts deleted file mode 100644 index fb5c45acf..000000000 --- a/client/src/app/shared/misc/peertube-local-storage.ts +++ /dev/null @@ -1,70 +0,0 @@ -// Thanks: https://github.com/capaj/localstorage-polyfill - -const valuesMap = new Map() - -class MemoryStorage { - [key: string]: any - [index: number]: string - - getItem (key: any) { - const stringKey = String(key) - if (valuesMap.has(key)) { - return String(valuesMap.get(stringKey)) - } - - return null - } - - setItem (key: any, val: any) { - valuesMap.set(String(key), String(val)) - } - - removeItem (key: any) { - valuesMap.delete(key) - } - - clear () { - valuesMap.clear() - } - - key (i: any) { - if (arguments.length === 0) { - throw new TypeError('Failed to execute "key" on "Storage": 1 argument required, but only 0 present.') - } - - const arr = Array.from(valuesMap.keys()) - return arr[i] - } - - get length () { - return valuesMap.size - } -} - -let peertubeLocalStorage: Storage -try { - peertubeLocalStorage = localStorage -} catch (err) { - const instance = new MemoryStorage() - - peertubeLocalStorage = new Proxy(instance, { - set: function (obj, prop: string | number, value) { - if (MemoryStorage.prototype.hasOwnProperty(prop)) { - instance[prop] = value - } else { - instance.setItem(prop, value) - } - return true - }, - get: function (target, name: string | number) { - if (MemoryStorage.prototype.hasOwnProperty(name)) { - return instance[name] - } - if (valuesMap.has(name)) { - return instance.getItem(name) - } - } - }) -} - -export { peertubeLocalStorage } diff --git a/client/src/app/shared/misc/peertube-web-storage.ts b/client/src/app/shared/misc/peertube-web-storage.ts new file mode 100644 index 000000000..fff209678 --- /dev/null +++ b/client/src/app/shared/misc/peertube-web-storage.ts @@ -0,0 +1,75 @@ +// Thanks: https://github.com/capaj/localstorage-polyfill + +const valuesMap = new Map() + +class MemoryStorage { + [key: string]: any + [index: number]: string + + getItem (key: any) { + const stringKey = String(key) + if (valuesMap.has(key)) { + return String(valuesMap.get(stringKey)) + } + + return null + } + + setItem (key: any, val: any) { + valuesMap.set(String(key), String(val)) + } + + removeItem (key: any) { + valuesMap.delete(key) + } + + clear () { + valuesMap.clear() + } + + key (i: any) { + if (arguments.length === 0) { + throw new TypeError('Failed to execute "key" on "Storage": 1 argument required, but only 0 present.') + } + + const arr = Array.from(valuesMap.keys()) + return arr[i] + } + + get length () { + return valuesMap.size + } +} + +let peertubeLocalStorage: Storage +let peertubeSessionStorage: Storage +try { + peertubeLocalStorage = localStorage + peertubeSessionStorage = sessionStorage +} catch (err) { + const instance = new MemoryStorage() + + peertubeLocalStorage = sessionStorage = new Proxy(instance, { + set: function (obj, prop: string | number, value) { + if (MemoryStorage.prototype.hasOwnProperty(prop)) { + instance[prop] = value + } else { + instance.setItem(prop, value) + } + return true + }, + get: function (target, name: string | number) { + if (MemoryStorage.prototype.hasOwnProperty(name)) { + return instance[name] + } + if (valuesMap.has(name)) { + return instance.getItem(name) + } + } + }) +} + +export { + peertubeLocalStorage, + peertubeSessionStorage +} diff --git a/client/src/app/shared/rest/rest-table.ts b/client/src/app/shared/rest/rest-table.ts index 884588207..c180346af 100644 --- a/client/src/app/shared/rest/rest-table.ts +++ b/client/src/app/shared/rest/rest-table.ts @@ -1,4 +1,4 @@ -import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' +import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage' import { LazyLoadEvent } from 'primeng/components/common/lazyloadevent' import { SortMeta } from 'primeng/components/common/sortmeta' import { RestPagination } from './rest-pagination' diff --git a/client/src/app/videos/+video-watch/video-watch-playlist.component.html b/client/src/app/videos/+video-watch/video-watch-playlist.component.html index c07ba1ed6..a04081d35 100644 --- a/client/src/app/videos/+video-watch/video-watch-playlist.component.html +++ b/client/src/app/videos/+video-watch/video-watch-playlist.component.html @@ -24,6 +24,15 @@ placement="bottom auto" container="body" > + + diff --git a/client/src/app/videos/+video-watch/video-watch-playlist.component.scss b/client/src/app/videos/+video-watch/video-watch-playlist.component.scss index ba8d1c3e1..0dd318cb0 100644 --- a/client/src/app/videos/+video-watch/video-watch-playlist.component.scss +++ b/client/src/app/videos/+video-watch/video-watch-playlist.component.scss @@ -39,6 +39,10 @@ display: flex; margin: 10px 0; + my-global-icon:not(:last-child) { + margin-right: .5rem; + } + my-global-icon { &:not(.active) { opacity: .5 diff --git a/client/src/app/videos/+video-watch/video-watch-playlist.component.ts b/client/src/app/videos/+video-watch/video-watch-playlist.component.ts index ed2aeda6e..c6b04fd4b 100644 --- a/client/src/app/videos/+video-watch/video-watch-playlist.component.ts +++ b/client/src/app/videos/+video-watch/video-watch-playlist.component.ts @@ -3,11 +3,11 @@ import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model' import { ComponentPagination } from '@app/shared/rest/component-pagination.model' import { VideoDetails, VideoPlaylistPrivacy } from '@shared/models' import { Router } from '@angular/router' -import { User, UserService } from '@app/shared' +import { UserService } from '@app/shared' import { AuthService, Notifier } from '@app/core' import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist-element.model' -import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' +import { peertubeLocalStorage, peertubeSessionStorage } from '@app/shared/misc/peertube-web-storage' import { I18n } from '@ngx-translate/i18n-polyfill' @Component({ @@ -17,6 +17,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill' }) export class VideoWatchPlaylistComponent { static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'auto_play_video_playlist' + static SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'loop_playlist' @Input() video: VideoDetails @Input() playlist: VideoPlaylist @@ -30,6 +31,8 @@ export class VideoWatchPlaylistComponent { autoPlayNextVideoPlaylist: boolean autoPlayNextVideoPlaylistSwitchText = '' + loopPlaylist: boolean + loopPlaylistSwitchText = '' noPlaylistVideos = false currentPlaylistPosition = 1 @@ -45,6 +48,9 @@ export class VideoWatchPlaylistComponent { ? this.auth.getUser().autoPlayNextVideoPlaylist : peertubeLocalStorage.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) !== 'false' this.setAutoPlayNextVideoPlaylistSwitchText() + + this.loopPlaylist = peertubeSessionStorage.getItem(VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true' + this.setLoopPlaylistSwitchText() } onPlaylistVideosNearOfBottom () { @@ -121,9 +127,9 @@ export class VideoWatchPlaylistComponent { this.onPlaylistVideosNearOfBottom() } - navigateToNextPlaylistVideo () { + navigateToNextPlaylistVideo (_next: VideoPlaylistElement = null) { if (this.currentPlaylistPosition < this.playlistPagination.totalItems) { - const next = this.playlistElements.find(e => e.position === this.currentPlaylistPosition + 1) + const next = _next || this.playlistElements.find(e => e.position === this.currentPlaylistPosition + 1) if (!next || !next.video) { this.currentPlaylistPosition++ @@ -134,6 +140,9 @@ export class VideoWatchPlaylistComponent { const start = next.startTimestamp const stop = next.stopTimestamp this.router.navigate([],{ queryParams: { videoId: next.video.uuid, start, stop } }) + } else if (this.loopPlaylist) { + this.currentPlaylistPosition = 0 + this.navigateToNextPlaylistVideo(this.playlistElements.find(e => e.position === this.currentPlaylistPosition)) } } @@ -160,9 +169,25 @@ export class VideoWatchPlaylistComponent { } } + switchLoopPlaylist () { + this.loopPlaylist = !this.loopPlaylist + this.setLoopPlaylistSwitchText() + + peertubeSessionStorage.setItem( + VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST, + this.loopPlaylist.toString() + ) + } + private setAutoPlayNextVideoPlaylistSwitchText () { - this.autoPlayNextVideoPlaylistSwitchText = this.i18n('{{verb}} autoplay for playlists', { - verb: this.autoPlayNextVideoPlaylist ? this.i18n('Disable') : this.i18n('Enable') - }) + this.autoPlayNextVideoPlaylistSwitchText = this.autoPlayNextVideoPlaylist + ? this.i18n('Stop autoplaying next video') + : this.i18n('Autoplay next video') + } + + private setLoopPlaylistSwitchText () { + this.loopPlaylistSwitchText = this.loopPlaylist + ? this.i18n('Stop looping playlist videos') + : this.i18n('Loop playlist videos') } } 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 92c1c50c0..aaaa63d4d 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts @@ -2,7 +2,7 @@ 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' -import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' +import { peertubeLocalStorage, peertubeSessionStorage } from '@app/shared/misc/peertube-web-storage' import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' import { MetaService } from '@ngx-meta/core' import { AuthUser, Notifier, ServerService } from '@app/core' @@ -46,7 +46,6 @@ import { RecommendedVideosComponent } from '../recommendations/recommended-video }) export class VideoWatchComponent implements OnInit, OnDestroy { private static LOCAL_STORAGE_PRIVACY_CONCERN_KEY = 'video-watch-privacy-concern' - private static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO = 'auto_play_next_video' @ViewChild('videoWatchPlaylist', { static: true }) videoWatchPlaylist: VideoWatchPlaylistComponent @ViewChild('videoShareModal', { static: false }) videoShareModal: VideoShareComponent @@ -439,11 +438,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy { if (this.playlist) { if ( this.user && this.user.autoPlayNextVideoPlaylist || - peertubeLocalStorage.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true' + peertubeSessionStorage.getItem(VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true' ) this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo()) } else if ( this.user && this.user.autoPlayNextVideo || - peertubeLocalStorage.getItem(RecommendedVideosComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true' + peertubeSessionStorage.getItem(RecommendedVideosComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true' ) { this.zone.run(() => this.autoplayNext()) } @@ -453,7 +452,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { if (this.playlist) { if ( this.user && this.user.autoPlayNextVideoPlaylist || - peertubeLocalStorage.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true' + peertubeSessionStorage.getItem(VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true' ) this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo()) } }) diff --git a/client/src/app/videos/recommendations/recommended-videos.component.ts b/client/src/app/videos/recommendations/recommended-videos.component.ts index 771ae54a2..fdcfb28e3 100644 --- a/client/src/app/videos/recommendations/recommended-videos.component.ts +++ b/client/src/app/videos/recommendations/recommended-videos.component.ts @@ -7,7 +7,7 @@ import { RecommendedVideosStore } from '@app/videos/recommendations/recommended- import { User } from '@app/shared' import { AuthService, Notifier } from '@app/core' import { UserService } from '@app/shared/users/user.service' -import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' +import { peertubeSessionStorage } from '@app/shared/misc/peertube-web-storage' @Component({ selector: 'my-recommended-videos', @@ -15,7 +15,7 @@ import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' styleUrls: [ './recommended-videos.component.scss' ] }) export class RecommendedVideosComponent implements OnChanges { - static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO = 'auto_play_next_video' + static SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO = 'auto_play_next_video' @Input() inputRecommendation: RecommendationInfo @Input() user: User @@ -39,7 +39,7 @@ export class RecommendedVideosComponent implements OnChanges { this.autoPlayNextVideo = this.authService.isLoggedIn() ? this.authService.getUser().autoPlayNextVideo - : peertubeLocalStorage.getItem(RecommendedVideosComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true' || false + : peertubeSessionStorage.getItem(RecommendedVideosComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true' || false } public ngOnChanges (): void { @@ -53,7 +53,7 @@ export class RecommendedVideosComponent implements OnChanges { } switchAutoPlayNextVideo () { - peertubeLocalStorage.setItem(RecommendedVideosComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO, this.autoPlayNextVideo.toString()) + peertubeSessionStorage.setItem(RecommendedVideosComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO, this.autoPlayNextVideo.toString()) if (this.authService.isLoggedIn()) { const details = { diff --git a/client/src/assets/images/global/repeat.svg b/client/src/assets/images/global/repeat.svg new file mode 100644 index 000000000..c7657b08e --- /dev/null +++ b/client/src/assets/images/global/repeat.svg @@ -0,0 +1 @@ + \ No newline at end of file