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'
-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)
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'
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'
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 {
'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'),
+++ /dev/null
-// 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 }
--- /dev/null
+// 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
+}
-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'
placement="bottom auto"
container="body"
></my-global-icon>
+
+ <my-global-icon
+ iconName="repeat"
+ [class.active]="loopPlaylist"
+ (click)="switchLoopPlaylist()"
+ [ngbTooltip]="'Loop playlist videos'"
+ placement="bottom auto"
+ container="body"
+ ></my-global-icon>
</div>
</div>
display: flex;
margin: 10px 0;
+ my-global-icon:not(:last-child) {
+ margin-right: .5rem;
+ }
+
my-global-icon {
&:not(.active) {
opacity: .5
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({
})
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
autoPlayNextVideoPlaylist: boolean
autoPlayNextVideoPlaylistSwitchText = ''
+ loopPlaylist: boolean
+ loopPlaylistSwitchText = ''
noPlaylistVideos = false
currentPlaylistPosition = 1
? 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 () {
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++
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))
}
}
}
}
+ 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')
}
}
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'
})
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
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())
}
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())
}
})
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',
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
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 {
}
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 = {
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-repeat"><polyline points="17 1 21 5 17 9"></polyline><path d="M3 11V9a4 4 0 0 1 4-4h14"></path><polyline points="7 23 3 19 7 15"></polyline><path d="M21 13v2a4 4 0 0 1-4 4H3"></path></svg>
\ No newline at end of file