video-watch-playlist.component.ts 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import { Component, Input } from '@angular/core'
  2. import { Router } from '@angular/router'
  3. import { AuthService, ComponentPagination, LocalStorageService, Notifier, SessionStorageService, UserService } from '@app/core'
  4. import { peertubeLocalStorage, peertubeSessionStorage } from '@root-helpers/peertube-web-storage'
  5. import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist'
  6. import { I18n } from '@ngx-translate/i18n-polyfill'
  7. import { VideoDetails, VideoPlaylistPrivacy } from '@shared/models'
  8. @Component({
  9. selector: 'my-video-watch-playlist',
  10. templateUrl: './video-watch-playlist.component.html',
  11. styleUrls: [ './video-watch-playlist.component.scss' ]
  12. })
  13. export class VideoWatchPlaylistComponent {
  14. static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'auto_play_video_playlist'
  15. static SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'loop_playlist'
  16. @Input() video: VideoDetails
  17. @Input() playlist: VideoPlaylist
  18. playlistElements: VideoPlaylistElement[] = []
  19. playlistPagination: ComponentPagination = {
  20. currentPage: 1,
  21. itemsPerPage: 30,
  22. totalItems: null
  23. }
  24. autoPlayNextVideoPlaylist: boolean
  25. autoPlayNextVideoPlaylistSwitchText = ''
  26. loopPlaylist: boolean
  27. loopPlaylistSwitchText = ''
  28. noPlaylistVideos = false
  29. currentPlaylistPosition = 1
  30. constructor (
  31. private userService: UserService,
  32. private auth: AuthService,
  33. private notifier: Notifier,
  34. private i18n: I18n,
  35. private videoPlaylist: VideoPlaylistService,
  36. private localStorageService: LocalStorageService,
  37. private sessionStorageService: SessionStorageService,
  38. private router: Router
  39. ) {
  40. // defaults to true
  41. this.autoPlayNextVideoPlaylist = this.auth.isLoggedIn()
  42. ? this.auth.getUser().autoPlayNextVideoPlaylist
  43. : this.localStorageService.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) !== 'false'
  44. this.setAutoPlayNextVideoPlaylistSwitchText()
  45. // defaults to false
  46. this.loopPlaylist = this.sessionStorageService.getItem(VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true'
  47. this.setLoopPlaylistSwitchText()
  48. }
  49. onPlaylistVideosNearOfBottom () {
  50. // Last page
  51. if (this.playlistPagination.totalItems <= (this.playlistPagination.currentPage * this.playlistPagination.itemsPerPage)) return
  52. this.playlistPagination.currentPage += 1
  53. this.loadPlaylistElements(this.playlist,false)
  54. }
  55. onElementRemoved (playlistElement: VideoPlaylistElement) {
  56. this.playlistElements = this.playlistElements.filter(e => e.id !== playlistElement.id)
  57. this.playlistPagination.totalItems--
  58. }
  59. isPlaylistOwned () {
  60. return this.playlist.isLocal === true &&
  61. this.auth.isLoggedIn() &&
  62. this.playlist.ownerAccount.name === this.auth.getUser().username
  63. }
  64. isUnlistedPlaylist () {
  65. return this.playlist.privacy.id === VideoPlaylistPrivacy.UNLISTED
  66. }
  67. isPrivatePlaylist () {
  68. return this.playlist.privacy.id === VideoPlaylistPrivacy.PRIVATE
  69. }
  70. isPublicPlaylist () {
  71. return this.playlist.privacy.id === VideoPlaylistPrivacy.PUBLIC
  72. }
  73. loadPlaylistElements (playlist: VideoPlaylist, redirectToFirst = false) {
  74. this.videoPlaylist.getPlaylistVideos(playlist.uuid, this.playlistPagination)
  75. .subscribe(({ total, data }) => {
  76. this.playlistElements = this.playlistElements.concat(data)
  77. this.playlistPagination.totalItems = total
  78. const firstAvailableVideos = this.playlistElements.find(e => !!e.video)
  79. if (!firstAvailableVideos) {
  80. this.noPlaylistVideos = true
  81. return
  82. }
  83. this.updatePlaylistIndex(this.video)
  84. if (redirectToFirst) {
  85. const extras = {
  86. queryParams: {
  87. start: firstAvailableVideos.startTimestamp,
  88. stop: firstAvailableVideos.stopTimestamp,
  89. videoId: firstAvailableVideos.video.uuid
  90. },
  91. replaceUrl: true
  92. }
  93. this.router.navigate([], extras)
  94. }
  95. })
  96. }
  97. updatePlaylistIndex (video: VideoDetails) {
  98. if (this.playlistElements.length === 0 || !video) return
  99. for (const playlistElement of this.playlistElements) {
  100. if (playlistElement.video && playlistElement.video.id === video.id) {
  101. this.currentPlaylistPosition = playlistElement.position
  102. return
  103. }
  104. }
  105. // Load more videos to find our video
  106. this.onPlaylistVideosNearOfBottom()
  107. }
  108. findNextPlaylistVideo (position = this.currentPlaylistPosition): VideoPlaylistElement {
  109. if (this.currentPlaylistPosition >= this.playlistPagination.totalItems) {
  110. // we have reached the end of the playlist: either loop or stop
  111. if (this.loopPlaylist) {
  112. this.currentPlaylistPosition = position = 0
  113. } else {
  114. return
  115. }
  116. }
  117. const next = this.playlistElements.find(e => e.position === position)
  118. if (!next || !next.video) {
  119. return this.findNextPlaylistVideo(position + 1)
  120. }
  121. return next
  122. }
  123. navigateToNextPlaylistVideo () {
  124. const next = this.findNextPlaylistVideo(this.currentPlaylistPosition + 1)
  125. if (!next) return
  126. const start = next.startTimestamp
  127. const stop = next.stopTimestamp
  128. this.router.navigate([],{ queryParams: { videoId: next.video.uuid, start, stop } })
  129. }
  130. switchAutoPlayNextVideoPlaylist () {
  131. this.autoPlayNextVideoPlaylist = !this.autoPlayNextVideoPlaylist
  132. this.setAutoPlayNextVideoPlaylistSwitchText()
  133. peertubeLocalStorage.setItem(
  134. VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST,
  135. this.autoPlayNextVideoPlaylist.toString()
  136. )
  137. if (this.auth.isLoggedIn()) {
  138. const details = {
  139. autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist
  140. }
  141. this.userService.updateMyProfile(details).subscribe(
  142. () => {
  143. this.auth.refreshUserInformation()
  144. },
  145. err => this.notifier.error(err.message)
  146. )
  147. }
  148. }
  149. switchLoopPlaylist () {
  150. this.loopPlaylist = !this.loopPlaylist
  151. this.setLoopPlaylistSwitchText()
  152. peertubeSessionStorage.setItem(
  153. VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST,
  154. this.loopPlaylist.toString()
  155. )
  156. }
  157. private setAutoPlayNextVideoPlaylistSwitchText () {
  158. this.autoPlayNextVideoPlaylistSwitchText = this.autoPlayNextVideoPlaylist
  159. ? this.i18n('Stop autoplaying next video')
  160. : this.i18n('Autoplay next video')
  161. }
  162. private setLoopPlaylistSwitchText () {
  163. this.loopPlaylistSwitchText = this.loopPlaylist
  164. ? this.i18n('Stop looping playlist videos')
  165. : this.i18n('Loop playlist videos')
  166. }
  167. }