-::ng-deep svg {
- width: inherit;
- height: inherit;
+::ng-deep {
+ svg {
+ width: inherit;
+ height: inherit;
+ }
}
autoPlayVideo: boolean
autoPlayNextVideo: boolean
+ autoPlayNextVideoPlaylist: boolean
webTorrentEnabled: boolean
videosHistoryEnabled: boolean
videoLanguages: string[]
a {
width: auto;
-
- &:hover {
- text-decoration: underline !important;
- }
}
.video-info-account, .video-info-timestamp {
<span>{{ currentPlaylistPosition }}</span><span>{{ playlistPagination.totalItems }}</span>
</div>
</div>
+
+ <div class="playlist-controls">
+ <my-global-icon
+ iconName="videos"
+ [class.active]="autoPlayNextVideoPlaylist"
+ (click)="switchAutoPlayNextVideoPlaylist()"
+ [ngbTooltip]="autoPlayNextVideoPlaylistSwitchText"
+ placement="bottom auto"
+ container="body"
+ ></my-global-icon>
+ </div>
</div>
<div *ngFor="let playlistElement of playlistElements">
margin: 0 3px;
}
}
+
+ .playlist-controls {
+ display: flex;
+ margin: 10px 0;
+
+ my-global-icon {
+ &:not(.active) {
+ opacity: .5
+ }
+
+ ::ng-deep {
+ cursor: pointer;
+ }
+ }
+ }
}
my-video-playlist-element-miniature {
import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
import { VideoDetails, VideoPlaylistPrivacy } from '@shared/models'
import { Router } from '@angular/router'
-import { AuthService } from '@app/core'
+import { User, 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 { I18n } from '@ngx-translate/i18n-polyfill'
@Component({
selector: 'my-video-watch-playlist',
styleUrls: [ './video-watch-playlist.component.scss' ]
})
export class VideoWatchPlaylistComponent {
+ static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'auto_play_video_playlist'
+
@Input() video: VideoDetails
@Input() playlist: VideoPlaylist
totalItems: null
}
+ autoPlayNextVideoPlaylist: boolean
+ autoPlayNextVideoPlaylistSwitchText = ''
noPlaylistVideos = false
currentPlaylistPosition = 1
constructor (
+ private userService: UserService,
private auth: AuthService,
+ private notifier: Notifier,
+ private i18n: I18n,
private videoPlaylist: VideoPlaylistService,
private router: Router
- ) {}
+ ) {
+ this.autoPlayNextVideoPlaylist = this.auth.isLoggedIn()
+ ? this.auth.getUser().autoPlayNextVideoPlaylist
+ : peertubeLocalStorage.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) !== 'false'
+ this.setAutoPlayNextVideoPlaylistSwitchText()
+ }
onPlaylistVideosNearOfBottom () {
// Last page
this.router.navigate([],{ queryParams: { videoId: next.video.uuid, start, stop } })
}
}
+
+ switchAutoPlayNextVideoPlaylist () {
+ this.autoPlayNextVideoPlaylist = !this.autoPlayNextVideoPlaylist
+ this.setAutoPlayNextVideoPlaylistSwitchText()
+
+ peertubeLocalStorage.setItem(
+ VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST,
+ this.autoPlayNextVideoPlaylist.toString()
+ )
+
+ if (this.auth.isLoggedIn()) {
+ const details = {
+ autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist
+ }
+
+ this.userService.updateMyProfile(details).subscribe(
+ () => {
+ this.auth.refreshUserInformation()
+ },
+ err => this.notifier.error(err.message)
+ )
+ }
+ }
+
+ private setAutoPlayNextVideoPlaylistSwitchText () {
+ this.autoPlayNextVideoPlaylistSwitchText = this.i18n('{{verb}} autoplay for playlists', {
+ verb: this.autoPlayNextVideoPlaylist ? this.i18n('Disable') : this.i18n('Enable')
+ })
+ }
}
<my-recommended-videos
[inputRecommendation]="{ uuid: video.uuid, tags: video.tags }"
[user]="user"
+ [playlist]="playlist"
(gotRecommendations)="onRecommendations($event)"
></my-recommended-videos>
</div>
import { HooksService } from '@app/core/plugins/hooks.service'
import { PlatformLocation } from '@angular/common'
import { randomInt } from '@shared/core-utils/miscs/miscs'
+import { RecommendedVideosComponent } from '../recommendations/recommended-videos.component'
@Component({
selector: 'my-video-watch',
this.player.one('ended', () => {
if (this.playlist) {
- this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo())
+ if (
+ this.user && this.user.autoPlayNextVideoPlaylist ||
+ peertubeLocalStorage.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true'
+ ) this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo())
} else if (
this.user && this.user.autoPlayNextVideo ||
- peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true'
+ peertubeLocalStorage.getItem(RecommendedVideosComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true'
) {
this.zone.run(() => this.autoplayNext())
}
this.player.one('stopped', () => {
if (this.playlist) {
- this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo())
+ if (
+ this.user && this.user.autoPlayNextVideoPlaylist ||
+ peertubeLocalStorage.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true'
+ ) this.zone.run(() => this.videoWatchPlaylist.navigateToNextPlaylistVideo())
}
})
import { RecommendationsModule } from '@app/videos/recommendations/recommendations.module'
import { VideoWatchPlaylistComponent } from '@app/videos/+video-watch/video-watch-playlist.component'
import { QRCodeModule } from 'angularx-qrcode'
+import { InputSwitchModule } from 'primeng/inputswitch'
@NgModule({
imports: [
SharedModule,
NgbTooltipModule,
QRCodeModule,
- RecommendationsModule
+ RecommendationsModule,
+ InputSwitchModule
],
declarations: [
<div i18n class="title-page title-page-single">
Other videos
</div>
- <div class="d-flex title-page-autoplay">
- <span>Autoplay</span>
+ <div *ngIf="!playlist" class="d-flex title-page-autoplay">
+ <span i18n>Autoplay</span>
<p-inputSwitch [(ngModel)]="autoPlayNextVideo" (ngModelChange)="switchAutoPlayNextVideo()"></p-inputSwitch>
</div>
</div>
- <div *ngFor="let video of (videos$ | async)">
+ <div *ngFor="let video of (videos$ | async); let i = index; let length = count">
<my-video-miniature [video]="video" [user]="user" (videoBlacklisted)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()">
</my-video-miniature>
+
+ <hr *ngIf="!playlist && i == 0 && length > 1" />
</div>
</ng-container>
</div>
import { Component, Input, Output, OnChanges, EventEmitter } from '@angular/core'
import { Observable } from 'rxjs'
import { Video } from '@app/shared/video/video.model'
+import { VideoPlaylist } from '@app/shared/video-playlist/video-playlist.model'
import { RecommendationInfo } from '@app/shared/video/recommendation-info.model'
import { RecommendedVideosStore } from '@app/videos/recommendations/recommended-videos.store'
import { User } from '@app/shared'
styleUrls: [ './recommended-videos.component.scss' ]
})
export class RecommendedVideosComponent implements OnChanges {
- private static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO = 'auto_play_next_video'
+ static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO = 'auto_play_next_video'
@Input() inputRecommendation: RecommendationInfo
@Input() user: User
+ @Input() playlist: VideoPlaylist
@Output() gotRecommendations = new EventEmitter<Video[]>()
readonly hasVideos$: Observable<boolean>
if (body.webTorrentEnabled !== undefined) user.webTorrentEnabled = body.webTorrentEnabled
if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo
if (body.autoPlayNextVideo !== undefined) user.autoPlayNextVideo = body.autoPlayNextVideo
+ if (body.autoPlayNextVideoPlaylist !== undefined) user.autoPlayNextVideoPlaylist = body.autoPlayNextVideoPlaylist
if (body.videosHistoryEnabled !== undefined) user.videosHistoryEnabled = body.videosHistoryEnabled
if (body.videoLanguages !== undefined) user.videoLanguages = body.videoLanguages
if (body.theme !== undefined) user.theme = body.theme
return isBooleanValid(value)
}
+function isUserAutoPlayNextVideoPlaylistValid (value: any) {
+ return isBooleanValid(value)
+}
+
function isNoInstanceConfigWarningModal (value: any) {
return isBooleanValid(value)
}
isUserWebTorrentEnabledValid,
isUserAutoPlayVideoValid,
isUserAutoPlayNextVideoValid,
+ isUserAutoPlayNextVideoPlaylistValid,
isUserDisplayNameValid,
isUserDescriptionValid,
isNoInstanceConfigWarningModal,
// ---------------------------------------------------------------------------
-const LAST_MIGRATION_VERSION = 455
+const LAST_MIGRATION_VERSION = 460
// ---------------------------------------------------------------------------
--- /dev/null
+import * as Sequelize from 'sequelize'
+
+async function up (utils: {
+ transaction: Sequelize.Transaction,
+ queryInterface: Sequelize.QueryInterface,
+ sequelize: Sequelize.Sequelize,
+ db: any
+}): Promise<void> {
+ {
+ const data = {
+ type: Sequelize.BOOLEAN,
+ allowNull: false,
+ defaultValue: true
+ }
+
+ await utils.queryInterface.addColumn('user', 'autoPlayNextVideoPlaylist', data)
+ }
+}
+
+function down (options) {
+ throw new Error('Not implemented.')
+}
+
+export {
+ up,
+ down
+}
isUserAdminFlagsValid,
isUserAutoPlayVideoValid,
isUserAutoPlayNextVideoValid,
+ isUserAutoPlayNextVideoPlaylistValid,
isUserBlockedReasonValid,
isUserBlockedValid,
isUserEmailVerifiedValid,
@Column
autoPlayNextVideo: boolean
+ @AllowNull(false)
+ @Default(true)
+ @Is('UserAutoPlayNextVideoPlaylist', value => throwIfNotValid(value, isUserAutoPlayNextVideoPlaylistValid, 'auto play next video for playlists boolean'))
+ @Column
+ autoPlayNextVideoPlaylist: boolean
+
@AllowNull(true)
@Default(null)
@Is('UserVideoLanguages', value => throwIfNotValid(value, isUserVideoLanguages, 'video languages'))
videosHistoryEnabled: this.videosHistoryEnabled,
autoPlayVideo: this.autoPlayVideo,
autoPlayNextVideo: this.autoPlayNextVideo,
+ autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist,
videoLanguages: this.videoLanguages,
role: this.role,
webTorrentEnabled?: boolean
autoPlayVideo?: boolean
autoPlayNextVideo?: boolean
+ autoPlayNextVideoPlaylist?: boolean
videosHistoryEnabled?: boolean
videoLanguages?: string[]
autoPlayVideo: boolean
autoPlayNextVideo: boolean
+ autoPlayNextVideoPlaylist: boolean
webTorrentEnabled: boolean
videosHistoryEnabled: boolean
videoLanguages: string[]