From a685e25ca05f08ad1b3f7fbaccc8744727bd8d27 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 9 Oct 2017 14:28:44 +0200 Subject: Try to optimize frontend --- client/src/app/app-routing.module.ts | 7 +- client/src/app/app.component.ts | 7 +- client/src/app/core/index.ts | 1 + client/src/app/core/routing/index.ts | 1 + .../core/routing/preload-selected-modules-list.ts | 16 ++ client/src/app/videos/+video-edit/index.ts | 2 + .../videos/+video-edit/video-add-routing.module.ts | 20 ++ .../videos/+video-edit/video-add.component.html | 121 +++++++++ .../app/videos/+video-edit/video-add.component.ts | 165 ++++++++++++ .../src/app/videos/+video-edit/video-add.module.ts | 30 +++ .../videos/+video-edit/video-edit.component.scss | 56 ++++ .../+video-edit/video-update-routing.module.ts | 20 ++ .../videos/+video-edit/video-update.component.html | 92 +++++++ .../videos/+video-edit/video-update.component.ts | 134 +++++++++ .../app/videos/+video-edit/video-update.module.ts | 30 +++ client/src/app/videos/+video-watch/index.ts | 1 + .../+video-watch/video-magnet.component.html | 20 ++ .../videos/+video-watch/video-magnet.component.ts | 27 ++ .../+video-watch/video-report.component.html | 38 +++ .../videos/+video-watch/video-report.component.ts | 69 +++++ .../videos/+video-watch/video-share.component.html | 29 ++ .../videos/+video-watch/video-share.component.ts | 42 +++ .../+video-watch/video-watch-routing.module.ts | 20 ++ .../videos/+video-watch/video-watch.component.html | 184 +++++++++++++ .../videos/+video-watch/video-watch.component.scss | 245 +++++++++++++++++ .../videos/+video-watch/video-watch.component.ts | 299 +++++++++++++++++++++ .../app/videos/+video-watch/video-watch.module.ts | 34 +++ client/src/app/videos/index.ts | 6 - client/src/app/videos/video-edit/index.ts | 2 - .../app/videos/video-edit/video-add.component.html | 121 --------- .../app/videos/video-edit/video-add.component.ts | 165 ------------ .../videos/video-edit/video-edit.component.scss | 56 ---- .../videos/video-edit/video-update.component.html | 92 ------- .../videos/video-edit/video-update.component.ts | 134 --------- client/src/app/videos/video-watch/index.ts | 4 - .../videos/video-watch/video-magnet.component.html | 20 -- .../videos/video-watch/video-magnet.component.ts | 27 -- .../videos/video-watch/video-report.component.html | 38 --- .../videos/video-watch/video-report.component.ts | 69 ----- .../videos/video-watch/video-share.component.html | 29 -- .../videos/video-watch/video-share.component.ts | 42 --- .../videos/video-watch/video-watch.component.html | 184 ------------- .../videos/video-watch/video-watch.component.scss | 245 ----------------- .../videos/video-watch/video-watch.component.ts | 299 --------------------- client/src/app/videos/videos-routing.module.ts | 11 +- client/src/app/videos/videos.component.ts | 12 +- client/src/app/videos/videos.module.ts | 19 -- 47 files changed, 1718 insertions(+), 1567 deletions(-) create mode 100644 client/src/app/core/routing/index.ts create mode 100644 client/src/app/core/routing/preload-selected-modules-list.ts create mode 100644 client/src/app/videos/+video-edit/index.ts create mode 100644 client/src/app/videos/+video-edit/video-add-routing.module.ts create mode 100644 client/src/app/videos/+video-edit/video-add.component.html create mode 100644 client/src/app/videos/+video-edit/video-add.component.ts create mode 100644 client/src/app/videos/+video-edit/video-add.module.ts create mode 100644 client/src/app/videos/+video-edit/video-edit.component.scss create mode 100644 client/src/app/videos/+video-edit/video-update-routing.module.ts create mode 100644 client/src/app/videos/+video-edit/video-update.component.html create mode 100644 client/src/app/videos/+video-edit/video-update.component.ts create mode 100644 client/src/app/videos/+video-edit/video-update.module.ts create mode 100644 client/src/app/videos/+video-watch/index.ts create mode 100644 client/src/app/videos/+video-watch/video-magnet.component.html create mode 100644 client/src/app/videos/+video-watch/video-magnet.component.ts create mode 100644 client/src/app/videos/+video-watch/video-report.component.html create mode 100644 client/src/app/videos/+video-watch/video-report.component.ts create mode 100644 client/src/app/videos/+video-watch/video-share.component.html create mode 100644 client/src/app/videos/+video-watch/video-share.component.ts create mode 100644 client/src/app/videos/+video-watch/video-watch-routing.module.ts create mode 100644 client/src/app/videos/+video-watch/video-watch.component.html create mode 100644 client/src/app/videos/+video-watch/video-watch.component.scss create mode 100644 client/src/app/videos/+video-watch/video-watch.component.ts create mode 100644 client/src/app/videos/+video-watch/video-watch.module.ts delete mode 100644 client/src/app/videos/video-edit/index.ts delete mode 100644 client/src/app/videos/video-edit/video-add.component.html delete mode 100644 client/src/app/videos/video-edit/video-add.component.ts delete mode 100644 client/src/app/videos/video-edit/video-edit.component.scss delete mode 100644 client/src/app/videos/video-edit/video-update.component.html delete mode 100644 client/src/app/videos/video-edit/video-update.component.ts delete mode 100644 client/src/app/videos/video-watch/index.ts delete mode 100644 client/src/app/videos/video-watch/video-magnet.component.html delete mode 100644 client/src/app/videos/video-watch/video-magnet.component.ts delete mode 100644 client/src/app/videos/video-watch/video-report.component.html delete mode 100644 client/src/app/videos/video-watch/video-report.component.ts delete mode 100644 client/src/app/videos/video-watch/video-share.component.html delete mode 100644 client/src/app/videos/video-watch/video-share.component.ts delete mode 100644 client/src/app/videos/video-watch/video-watch.component.html delete mode 100644 client/src/app/videos/video-watch/video-watch.component.scss delete mode 100644 client/src/app/videos/video-watch/video-watch.component.ts (limited to 'client/src') diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index 191ae6974..0f9484344 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts @@ -1,5 +1,7 @@ import { NgModule } from '@angular/core' -import { Routes, RouterModule, PreloadAllModules } from '@angular/router' +import { Routes, RouterModule } from '@angular/router' + +import { PreloadSelectedModulesList } from './core' const routes: Routes = [ { @@ -17,9 +19,10 @@ const routes: Routes = [ imports: [ RouterModule.forRoot(routes, { useHash: Boolean(history.pushState) === false, - preloadingStrategy: PreloadAllModules + preloadingStrategy: PreloadSelectedModulesList }) ], + providers: [ PreloadSelectedModulesList ], exports: [ RouterModule ] }) export class AppRoutingModule {} diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index ae86bc96f..82e647c98 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -2,7 +2,6 @@ import { Component, OnInit, ViewContainerRef } from '@angular/core' import { Router } from '@angular/router' import { AuthService, ConfigService } from './core' -import { VideoService } from './videos' import { UserService } from './shared' @Component({ @@ -30,8 +29,7 @@ export class AppComponent implements OnInit { private router: Router, private authService: AuthService, private configService: ConfigService, - private userService: UserService, - private videoService: VideoService + private userService: UserService ) {} ngOnInit () { @@ -43,9 +41,6 @@ export class AppComponent implements OnInit { } this.configService.loadConfig() - this.videoService.loadVideoCategories() - this.videoService.loadVideoLicences() - this.videoService.loadVideoLanguages() // Do not display menu on small screens if (window.innerWidth < 600) { diff --git a/client/src/app/core/index.ts b/client/src/app/core/index.ts index 01b12ce7e..31322138f 100644 --- a/client/src/app/core/index.ts +++ b/client/src/app/core/index.ts @@ -2,4 +2,5 @@ export * from './auth' export * from './config' export * from './confirm' export * from './menu' +export * from './routing' export * from './core.module' diff --git a/client/src/app/core/routing/index.ts b/client/src/app/core/routing/index.ts new file mode 100644 index 000000000..17f3ee833 --- /dev/null +++ b/client/src/app/core/routing/index.ts @@ -0,0 +1 @@ +export * from './preload-selected-modules-list' diff --git a/client/src/app/core/routing/preload-selected-modules-list.ts b/client/src/app/core/routing/preload-selected-modules-list.ts new file mode 100644 index 000000000..dd5be6ad9 --- /dev/null +++ b/client/src/app/core/routing/preload-selected-modules-list.ts @@ -0,0 +1,16 @@ +import { Route, PreloadingStrategy } from '@angular/router'; +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/timer'; +import 'rxjs/add/operator/switchMap'; + +export class PreloadSelectedModulesList implements PreloadingStrategy { + preload(route: Route, load: Function): Observable { + if (!route.data || !route.data.preload) return Observable.of(null); + + if (typeof route.data.preload === 'number') { + return Observable.timer(route.data.preload).switchMap(() => load()); + } + + return load(); + } +} diff --git a/client/src/app/videos/+video-edit/index.ts b/client/src/app/videos/+video-edit/index.ts new file mode 100644 index 000000000..63e0414dd --- /dev/null +++ b/client/src/app/videos/+video-edit/index.ts @@ -0,0 +1,2 @@ +export * from './video-add.module' +export * from './video-update.module' diff --git a/client/src/app/videos/+video-edit/video-add-routing.module.ts b/client/src/app/videos/+video-edit/video-add-routing.module.ts new file mode 100644 index 000000000..9e8fa4acc --- /dev/null +++ b/client/src/app/videos/+video-edit/video-add-routing.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core' +import { RouterModule, Routes } from '@angular/router' + +import { MetaGuard } from '@ngx-meta/core' + +import { VideoAddComponent } from './video-add.component' + +const videoAddRoutes: Routes = [ + { + path: '', + component: VideoAddComponent, + canActivateChild: [ MetaGuard ] + } +] + +@NgModule({ + imports: [ RouterModule.forChild(videoAddRoutes) ], + exports: [ RouterModule ] +}) +export class VideoAddRoutingModule {} diff --git a/client/src/app/videos/+video-edit/video-add.component.html b/client/src/app/videos/+video-edit/video-add.component.html new file mode 100644 index 000000000..698152ff9 --- /dev/null +++ b/client/src/app/videos/+video-edit/video-add.component.html @@ -0,0 +1,121 @@ +
+
+ +

Upload a video

+ +
{{ error }}
+ +
+
+ + +
+ {{ formErrors.name }} +
+
+ +
+ + +
+ +
+ + + +
+ {{ formErrors.category }} +
+
+ +
+ + + +
+ {{ formErrors.licence }} +
+
+ +
+ + + +
+ {{ formErrors.language }} +
+
+ +
+ (press enter to add the tag) + +
+ +
+ +
+ Select the video... + + +
+
+ +
+
+ {{ filename }} + +
+
+ +
+ {{ formErrors.videofile }} +
+ +
+ + +
+ {{ formErrors.description }} +
+
+ +
+ + + + Server is processing the video + + +
+ +
+ +
+
+
+
diff --git a/client/src/app/videos/+video-edit/video-add.component.ts b/client/src/app/videos/+video-edit/video-add.component.ts new file mode 100644 index 000000000..21311b184 --- /dev/null +++ b/client/src/app/videos/+video-edit/video-add.component.ts @@ -0,0 +1,165 @@ +import { Component, OnInit, ViewChild } from '@angular/core' +import { FormBuilder, FormGroup } from '@angular/forms' +import { Router } from '@angular/router' + +import { NotificationsService } from 'angular2-notifications' + +import { + FormReactive, + VIDEO_NAME, + VIDEO_CATEGORY, + VIDEO_LICENCE, + VIDEO_LANGUAGE, + VIDEO_DESCRIPTION, + VIDEO_TAGS +} from '../../shared' +import { VideoService } from '../shared' +import { VideoCreate } from '../../../../../shared' +import { HttpEventType, HttpResponse } from '@angular/common/http' +import { VIDEO_FILE } from '../../shared/forms/form-validators/video' + +@Component({ + selector: 'my-videos-add', + styleUrls: [ './video-edit.component.scss' ], + templateUrl: './video-add.component.html' +}) + +export class VideoAddComponent extends FormReactive implements OnInit { + @ViewChild('videofileInput') videofileInput + + progressPercent = 0 + tags: string[] = [] + videoCategories = [] + videoLicences = [] + videoLanguages = [] + + tagValidators = VIDEO_TAGS.VALIDATORS + tagValidatorsMessages = VIDEO_TAGS.MESSAGES + + error: string + form: FormGroup + formErrors = { + name: '', + category: '', + licence: '', + language: '', + description: '', + videofile: '' + } + validationMessages = { + name: VIDEO_NAME.MESSAGES, + category: VIDEO_CATEGORY.MESSAGES, + licence: VIDEO_LICENCE.MESSAGES, + language: VIDEO_LANGUAGE.MESSAGES, + description: VIDEO_DESCRIPTION.MESSAGES, + videofile: VIDEO_FILE.MESSAGES + } + + constructor ( + private formBuilder: FormBuilder, + private router: Router, + private notificationsService: NotificationsService, + private videoService: VideoService + ) { + super() + } + + get filename () { + return this.form.value['videofile'] + } + + buildForm () { + this.form = this.formBuilder.group({ + name: [ '', VIDEO_NAME.VALIDATORS ], + nsfw: [ false ], + category: [ '', VIDEO_CATEGORY.VALIDATORS ], + licence: [ '', VIDEO_LICENCE.VALIDATORS ], + language: [ '', VIDEO_LANGUAGE.VALIDATORS ], + description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], + videofile: [ '', VIDEO_FILE.VALIDATORS ], + tags: [ '' ] + }) + + this.form.valueChanges.subscribe(data => this.onValueChanged(data)) + } + + ngOnInit () { + this.videoCategories = this.videoService.videoCategories + this.videoLicences = this.videoService.videoLicences + this.videoLanguages = this.videoService.videoLanguages + + this.buildForm() + } + + // The goal is to keep reactive form validation (required field) + // https://stackoverflow.com/a/44238894 + fileChange ($event) { + this.form.controls['videofile'].setValue($event.target.files[0].name) + } + + removeFile () { + this.videofileInput.nativeElement.value = '' + this.form.controls['videofile'].setValue('') + } + + checkForm () { + this.forceCheck() + + return this.form.valid + } + + upload () { + if (this.checkForm() === false) { + return + } + + const formValue: VideoCreate = this.form.value + + const name = formValue.name + const nsfw = formValue.nsfw + const category = formValue.category + const licence = formValue.licence + const language = formValue.language + const description = formValue.description + const tags = formValue.tags + const videofile = this.videofileInput.nativeElement.files[0] + + const formData = new FormData() + formData.append('name', name) + formData.append('category', '' + category) + formData.append('nsfw', '' + nsfw) + formData.append('licence', '' + licence) + formData.append('videofile', videofile) + + // Language is optional + if (language) { + formData.append('language', '' + language) + } + + formData.append('description', description) + + for (let i = 0; i < tags.length; i++) { + formData.append(`tags[${i}]`, tags[i]) + } + + this.videoService.uploadVideo(formData).subscribe( + event => { + if (event.type === HttpEventType.UploadProgress) { + this.progressPercent = Math.round(100 * event.loaded / event.total) + } else if (event instanceof HttpResponse) { + console.log('Video uploaded.') + this.notificationsService.success('Success', 'Video uploaded.') + + // Display all the videos once it's finished + this.router.navigate([ '/videos/list' ]) + } + }, + + err => { + // Reset progress + this.progressPercent = 0 + this.error = err.message + } + ) + } +} diff --git a/client/src/app/videos/+video-edit/video-add.module.ts b/client/src/app/videos/+video-edit/video-add.module.ts new file mode 100644 index 000000000..141d33ad2 --- /dev/null +++ b/client/src/app/videos/+video-edit/video-add.module.ts @@ -0,0 +1,30 @@ +import { NgModule } from '@angular/core' + +import { TagInputModule } from 'ngx-chips' + +import { VideoAddRoutingModule } from './video-add-routing.module' +import { VideoAddComponent } from './video-add.component' +import { VideoService } from '../shared' +import { SharedModule } from '../../shared' + +@NgModule({ + imports: [ + TagInputModule, + + VideoAddRoutingModule, + SharedModule + ], + + declarations: [ + VideoAddComponent + ], + + exports: [ + VideoAddComponent + ], + + providers: [ + VideoService + ] +}) +export class VideoAddModule { } diff --git a/client/src/app/videos/+video-edit/video-edit.component.scss b/client/src/app/videos/+video-edit/video-edit.component.scss new file mode 100644 index 000000000..9ee0c520c --- /dev/null +++ b/client/src/app/videos/+video-edit/video-edit.component.scss @@ -0,0 +1,56 @@ +.btn-file { + position: relative; + overflow: hidden; + display: block; +} + +.btn-file input[type=file] { + position: absolute; + top: 0; + right: 0; + min-width: 100%; + min-height: 100%; + font-size: 100px; + text-align: right; + filter: alpha(opacity=0); + opacity: 0; + outline: none; + background: white; + cursor: inherit; + display: block; +} + +.form-group { + margin-bottom: 10px; +} + +div.tags { + height: 40px; + font-size: 20px; + margin-top: 20px; + + .tag { + margin-right: 10px; + + .remove { + cursor: pointer; + } + } +} + +div.file-to-upload { + height: 40px; + + .glyphicon-remove { + cursor: pointer; + } +} + +.little-information { + font-size: 0.8em; + font-style: italic; +} + +.label-tags { + margin-bottom: 0; +} diff --git a/client/src/app/videos/+video-edit/video-update-routing.module.ts b/client/src/app/videos/+video-edit/video-update-routing.module.ts new file mode 100644 index 000000000..1d06a7ac3 --- /dev/null +++ b/client/src/app/videos/+video-edit/video-update-routing.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core' +import { RouterModule, Routes } from '@angular/router' + +import { MetaGuard } from '@ngx-meta/core' + +import { VideoUpdateComponent } from './video-update.component' + +const videoUpdateRoutes: Routes = [ + { + path: '', + component: VideoUpdateComponent, + canActivateChild: [ MetaGuard ] + } +] + +@NgModule({ + imports: [ RouterModule.forChild(videoUpdateRoutes) ], + exports: [ RouterModule ] +}) +export class VideoUpdateRoutingModule {} diff --git a/client/src/app/videos/+video-edit/video-update.component.html b/client/src/app/videos/+video-edit/video-update.component.html new file mode 100644 index 000000000..7f4faf21b --- /dev/null +++ b/client/src/app/videos/+video-edit/video-update.component.html @@ -0,0 +1,92 @@ +
+
+ +

Update {{ video?.name }}

+ +
{{ error }}
+ +
+
+ + +
+ {{ formErrors.name }} +
+
+ +
+ + +
+ +
+ + + +
+ {{ formErrors.category }} +
+
+ +
+ + + +
+ {{ formErrors.licence }} +
+
+ +
+ + + +
+ {{ formErrors.language }} +
+
+ +
+ (press enter to add the tag) + +
+ +
+ + +
+ {{ formErrors.description }} +
+
+ +
+ +
+
+
+
diff --git a/client/src/app/videos/+video-edit/video-update.component.ts b/client/src/app/videos/+video-edit/video-update.component.ts new file mode 100644 index 000000000..141ed3522 --- /dev/null +++ b/client/src/app/videos/+video-edit/video-update.component.ts @@ -0,0 +1,134 @@ +import { Component, ElementRef, OnInit } from '@angular/core' +import { FormBuilder, FormGroup } from '@angular/forms' +import { ActivatedRoute, Router } from '@angular/router' + +import { NotificationsService } from 'angular2-notifications' + +import { AuthService } from '../../core' +import { + FormReactive, + VIDEO_NAME, + VIDEO_CATEGORY, + VIDEO_LICENCE, + VIDEO_LANGUAGE, + VIDEO_DESCRIPTION, + VIDEO_TAGS +} from '../../shared' +import { Video, VideoService } from '../shared' + +@Component({ + selector: 'my-videos-update', + styleUrls: [ './video-edit.component.scss' ], + templateUrl: './video-update.component.html' +}) + +export class VideoUpdateComponent extends FormReactive implements OnInit { + tags: string[] = [] + videoCategories = [] + videoLicences = [] + videoLanguages = [] + video: Video + + tagValidators = VIDEO_TAGS.VALIDATORS + tagValidatorsMessages = VIDEO_TAGS.MESSAGES + + error: string = null + form: FormGroup + formErrors = { + name: '', + category: '', + licence: '', + language: '', + description: '' + } + validationMessages = { + name: VIDEO_NAME.MESSAGES, + category: VIDEO_CATEGORY.MESSAGES, + licence: VIDEO_LICENCE.MESSAGES, + language: VIDEO_LANGUAGE.MESSAGES, + description: VIDEO_DESCRIPTION.MESSAGES + } + + fileError = '' + + constructor ( + private authService: AuthService, + private elementRef: ElementRef, + private formBuilder: FormBuilder, + private route: ActivatedRoute, + private router: Router, + private notificationsService: NotificationsService, + private videoService: VideoService + ) { + super() + } + + buildForm () { + this.form = this.formBuilder.group({ + name: [ '', VIDEO_NAME.VALIDATORS ], + nsfw: [ false ], + category: [ '', VIDEO_CATEGORY.VALIDATORS ], + licence: [ '', VIDEO_LICENCE.VALIDATORS ], + language: [ '', VIDEO_LANGUAGE.VALIDATORS ], + description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], + tags: [ '' ] + }) + + this.form.valueChanges.subscribe(data => this.onValueChanged(data)) + } + + ngOnInit () { + this.buildForm() + + this.videoCategories = this.videoService.videoCategories + this.videoLicences = this.videoService.videoLicences + this.videoLanguages = this.videoService.videoLanguages + + const uuid: string = this.route.snapshot.params['uuid'] + this.videoService.getVideo(uuid) + .subscribe( + video => { + this.video = video + + this.hydrateFormFromVideo() + }, + + err => { + console.error(err) + this.error = 'Cannot fetch video.' + } + ) + } + + checkForm () { + this.forceCheck() + + return this.form.valid + } + + update () { + if (this.checkForm() === false) { + return + } + + this.video.patch(this.form.value) + + this.videoService.updateVideo(this.video) + .subscribe( + () => { + this.notificationsService.success('Success', 'Video updated.') + this.router.navigate([ '/videos/watch', this.video.uuid ]) + }, + + err => { + this.error = 'Cannot update the video.' + console.error(err) + } + ) + + } + + private hydrateFormFromVideo () { + this.form.patchValue(this.video.toJSON()) + } +} diff --git a/client/src/app/videos/+video-edit/video-update.module.ts b/client/src/app/videos/+video-edit/video-update.module.ts new file mode 100644 index 000000000..eeb2e35e2 --- /dev/null +++ b/client/src/app/videos/+video-edit/video-update.module.ts @@ -0,0 +1,30 @@ +import { NgModule } from '@angular/core' + +import { TagInputModule } from 'ngx-chips' + +import { VideoUpdateRoutingModule } from './video-update-routing.module' +import { VideoUpdateComponent } from './video-update.component' +import { VideoService } from '../shared' +import { SharedModule } from '../../shared' + +@NgModule({ + imports: [ + TagInputModule, + + VideoUpdateRoutingModule, + SharedModule + ], + + declarations: [ + VideoUpdateComponent + ], + + exports: [ + VideoUpdateComponent + ], + + providers: [ + VideoService + ] +}) +export class VideoUpdateModule { } diff --git a/client/src/app/videos/+video-watch/index.ts b/client/src/app/videos/+video-watch/index.ts new file mode 100644 index 000000000..b19bfdb1e --- /dev/null +++ b/client/src/app/videos/+video-watch/index.ts @@ -0,0 +1 @@ +export * from './video-watch.module' diff --git a/client/src/app/videos/+video-watch/video-magnet.component.html b/client/src/app/videos/+video-watch/video-magnet.component.html new file mode 100644 index 000000000..484280c45 --- /dev/null +++ b/client/src/app/videos/+video-watch/video-magnet.component.html @@ -0,0 +1,20 @@ + diff --git a/client/src/app/videos/+video-watch/video-magnet.component.ts b/client/src/app/videos/+video-watch/video-magnet.component.ts new file mode 100644 index 000000000..f9432e92c --- /dev/null +++ b/client/src/app/videos/+video-watch/video-magnet.component.ts @@ -0,0 +1,27 @@ +import { Component, Input, ViewChild } from '@angular/core' + +import { ModalDirective } from 'ngx-bootstrap/modal' + +import { Video } from '../shared' + +@Component({ + selector: 'my-video-magnet', + templateUrl: './video-magnet.component.html' +}) +export class VideoMagnetComponent { + @Input() video: Video = null + + @ViewChild('modal') modal: ModalDirective + + constructor () { + // empty + } + + show () { + this.modal.show() + } + + hide () { + this.modal.hide() + } +} diff --git a/client/src/app/videos/+video-watch/video-report.component.html b/client/src/app/videos/+video-watch/video-report.component.html new file mode 100644 index 000000000..741080ead --- /dev/null +++ b/client/src/app/videos/+video-watch/video-report.component.html @@ -0,0 +1,38 @@ + diff --git a/client/src/app/videos/+video-watch/video-report.component.ts b/client/src/app/videos/+video-watch/video-report.component.ts new file mode 100644 index 000000000..d9c83a640 --- /dev/null +++ b/client/src/app/videos/+video-watch/video-report.component.ts @@ -0,0 +1,69 @@ +import { Component, Input, OnInit, ViewChild } from '@angular/core' +import { FormBuilder, FormGroup } from '@angular/forms' + +import { ModalDirective } from 'ngx-bootstrap/modal' +import { NotificationsService } from 'angular2-notifications' + +import { FormReactive, VideoAbuseService, VIDEO_ABUSE_REASON } from '../../shared' +import { Video, VideoService } from '../shared' + +@Component({ + selector: 'my-video-report', + templateUrl: './video-report.component.html' +}) +export class VideoReportComponent extends FormReactive implements OnInit { + @Input() video: Video = null + + @ViewChild('modal') modal: ModalDirective + + error: string = null + form: FormGroup + formErrors = { + reason: '' + } + validationMessages = { + reason: VIDEO_ABUSE_REASON.MESSAGES + } + + constructor ( + private formBuilder: FormBuilder, + private videoAbuseService: VideoAbuseService, + private notificationsService: NotificationsService + ) { + super() + } + + ngOnInit () { + this.buildForm() + } + + buildForm () { + this.form = this.formBuilder.group({ + reason: [ '', VIDEO_ABUSE_REASON.VALIDATORS ] + }) + + this.form.valueChanges.subscribe(data => this.onValueChanged(data)) + } + + show () { + this.modal.show() + } + + hide () { + this.modal.hide() + } + + report () { + const reason = this.form.value['reason'] + + this.videoAbuseService.reportVideo(this.video.id, reason) + .subscribe( + () => { + this.notificationsService.success('Success', 'Video reported.') + this.hide() + }, + + err => this.notificationsService.error('Error', err.message) + ) + } +} diff --git a/client/src/app/videos/+video-watch/video-share.component.html b/client/src/app/videos/+video-watch/video-share.component.html new file mode 100644 index 000000000..88f59c063 --- /dev/null +++ b/client/src/app/videos/+video-watch/video-share.component.html @@ -0,0 +1,29 @@ + diff --git a/client/src/app/videos/+video-watch/video-share.component.ts b/client/src/app/videos/+video-watch/video-share.component.ts new file mode 100644 index 000000000..133f93498 --- /dev/null +++ b/client/src/app/videos/+video-watch/video-share.component.ts @@ -0,0 +1,42 @@ +import { Component, Input, ViewChild } from '@angular/core' + +import { ModalDirective } from 'ngx-bootstrap/modal' + +import { Video } from '../shared' + +@Component({ + selector: 'my-video-share', + templateUrl: './video-share.component.html' +}) +export class VideoShareComponent { + @Input() video: Video = null + + @ViewChild('modal') modal: ModalDirective + + constructor () { + // empty + } + + show () { + this.modal.show() + } + + hide () { + this.modal.hide() + } + + getVideoIframeCode () { + return '' + } + + getVideoUrl () { + return window.location.href + } + + notSecure () { + return window.location.protocol === 'http:' + } +} diff --git a/client/src/app/videos/+video-watch/video-watch-routing.module.ts b/client/src/app/videos/+video-watch/video-watch-routing.module.ts new file mode 100644 index 000000000..97fa5c725 --- /dev/null +++ b/client/src/app/videos/+video-watch/video-watch-routing.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core' +import { RouterModule, Routes } from '@angular/router' + +import { MetaGuard } from '@ngx-meta/core' + +import { VideoWatchComponent } from './video-watch.component' + +const videoWatchRoutes: Routes = [ + { + path: '', + component: VideoWatchComponent, + canActivateChild: [ MetaGuard ] + } +] + +@NgModule({ + imports: [ RouterModule.forChild(videoWatchRoutes) ], + exports: [ RouterModule ] +}) +export class VideoWatchRoutingModule {} diff --git a/client/src/app/videos/+video-watch/video-watch.component.html b/client/src/app/videos/+video-watch/video-watch.component.html new file mode 100644 index 000000000..88863131a --- /dev/null +++ b/client/src/app/videos/+video-watch/video-watch.component.html @@ -0,0 +1,184 @@ +
+
+ The video load seems to be abnormally long. + +
+
+ +
+ +
+ +
+ +
Video not found :'(
+
+ + +
+
Download: {{ downloadSpeed | bytes }}/s
+
Upload: {{ uploadSpeed | bytes }}/s
+
Number of peers: {{ numPeers }}
+
+ + +
+
+
+ {{ video.name }} +
+ +
+ {{ video.views}} views +
+
+ +
+ + + + + + +
+
+ + + + {{ video.likes }} + +
+ +
+ + + + {{ video.dislikes }} + +
+
+
+ +
+
+
+ Published on {{ video.createdAt | date:'short' }} +
+ +
+ {{ video.description }} +
+
+ +
+
+ + Category: + + + {{ video.categoryLabel }} + +
+ +
+ + Licence: + + + {{ video.licenceLabel }} + +
+ +
+ + Language: + + + {{ video.languageLabel }} + +
+ +
+ + Tags: + + + +
+ +
+
+
+ + + + + + diff --git a/client/src/app/videos/+video-watch/video-watch.component.scss b/client/src/app/videos/+video-watch/video-watch.component.scss new file mode 100644 index 000000000..69661747c --- /dev/null +++ b/client/src/app/videos/+video-watch/video-watch.component.scss @@ -0,0 +1,245 @@ +#video-container { + width: 100%; + height: 100%; +} + +#video-not-found { + height: 300px; + line-height: 300px; + margin-top: 50px; + text-align: center; + font-weight: bold; +} + +.embed-responsive { + height: 500px; + + @media screen and (max-width: 600px) { + height: 300px; + } +} + +#torrent-info { + font-size: 10px; + margin-top: 10px; + text-align: center; + + div { + min-width: 60px; + } +} + +#video-info { + .video-name-views { + font-weight: bold; + font-size: 18px; + height: $video-watch-title-height; + line-height: $video-watch-title-height; + + .video-name { + padding-left: $video-watch-info-padding-left; + } + + .video-views { + text-align: right; + // Keep a symmetry with the video name + padding-right: $video-watch-info-padding-left + } + + } + + .video-small-blocks { + height: $video-watch-info-height; + color: $video-watch-info-color; + border-color: $video-watch-border-color; + border-width: 1px 0px; + border-style: solid; + + .video-small-block { + height: $video-watch-info-height; + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; + + a { + cursor: pointer; + transition: color 0.3s; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + &, &:hover { + color: inherit; + text-decoration:none; + } + + &:hover { + color: #000 !important; + } + + &:hover > .glyphicon { + opacity: 1 !important; + } + } + + .option .glyphicon { + font-size: 22px; + color: inherit; + opacity: 0.15; + margin-bottom: 10px; + transition: opacity 0.3s; + } + + .video-small-block-text { + font-size: 15px; + font-weight: bold; + } + } + + .video-small-block:not(:last-child) { + border-width: 0 1px 0 0; + border-color: $video-watch-border-color; + border-style: solid; + } + + .video-small-block-author, .video-small-block-more { + a.option { + display: block; + + .glyphicon { + display: block; + } + } + } + + .video-small-block-share, .video-small-block-more { + a.option { + display: block; + + .glyphicon { + display: block; + } + } + } + + .video-small-block-more .video-small-block-dropdown { + position: relative; + + .dropdown-item .glyphicon { + margin-right: 5px; + } + } + + .video-small-block-rating { + + .video-small-block-like { + margin-bottom: 10px; + } + + .video-small-block-text { + vertical-align: top; + } + + .glyphicon { + font-size: 18px; + margin: 0 10px 0 0; + opacity: 0.3; + } + + .interactive { + cursor: pointer; + transition: opacity, color 0.3s; + + &.activated, &:hover { + opacity: 1; + color: #000; + } + } + } + } + + .video-details { + margin-top: 30px; + + .video-details-date-description { + padding-left: $video-watch-info-padding-left; + + .video-details-date { + font-weight: bold; + margin-bottom: 30px; + } + } + + .video-details-attributes { + font-weight: bold; + font-size: 12px; + + .video-details-attribute-label { + color: $video-watch-info-color; + display: inline-block; + width: 60px; + margin-right: 5px; + } + } + + .video-details-tags { + display: inline-block; + + a { + display: inline-block; + margin-right: 3px; + font-size: 11px; + } + } + } + + @media screen and (max-width: 400px) { + .video-name-views { + font-size: 16px !important; + } + } + + @media screen and (max-width: 800px) { + .video-name-views { + .video-name { + padding-left: 5px; + padding-right: 0px; + } + + .video-views { + padding-left: 0px; + padding-right: 5px; + } + } + + .video-small-blocks { + a, .video-small-block-text { + font-size: 13px !important; + } + + .glyphicon { + font-size: 18px !important; + } + + .video-small-block-author { + padding-left: 10px; + } + } + + .video-details { + .video-details-date-description { + padding-left: 10px; + font-size: 13px !important; + } + + .video-details-attributes { + font-size: 11px !important; + + .video-details-attribute-label { + width: 50px; + } + } + } + } +} diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts new file mode 100644 index 000000000..874dd5997 --- /dev/null +++ b/client/src/app/videos/+video-watch/video-watch.component.ts @@ -0,0 +1,299 @@ +import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core' +import { ActivatedRoute, Router } from '@angular/router' +import { Observable } from 'rxjs/Observable' +import { Subscription } from 'rxjs/Subscription' + +import videojs from 'video.js' +import '../../../assets/player/peertube-videojs-plugin' + +import { MetaService } from '@ngx-meta/core' +import { NotificationsService } from 'angular2-notifications' + +import { AuthService, ConfirmService } from '../../core' +import { VideoMagnetComponent } from './video-magnet.component' +import { VideoShareComponent } from './video-share.component' +import { VideoReportComponent } from './video-report.component' +import { Video, VideoService } from '../shared' +import { WebTorrentService } from './webtorrent.service' +import { UserVideoRateType, VideoRateType } from '../../../../../shared' + +@Component({ + selector: 'my-video-watch', + templateUrl: './video-watch.component.html', + styleUrls: [ './video-watch.component.scss' ] +}) +export class VideoWatchComponent implements OnInit, OnDestroy { + @ViewChild('videoMagnetModal') videoMagnetModal: VideoMagnetComponent + @ViewChild('videoShareModal') videoShareModal: VideoShareComponent + @ViewChild('videoReportModal') videoReportModal: VideoReportComponent + + downloadSpeed: number + error = false + loading = false + numPeers: number + player: videojs.Player + playerElement: HTMLMediaElement + uploadSpeed: number + userRating: UserVideoRateType = null + video: Video = null + videoNotFound = false + + private paramsSub: Subscription + + constructor ( + private elementRef: ElementRef, + private route: ActivatedRoute, + private router: Router, + private videoService: VideoService, + private confirmService: ConfirmService, + private metaService: MetaService, + private authService: AuthService, + private notificationsService: NotificationsService + ) {} + + ngOnInit () { + this.paramsSub = this.route.params.subscribe(routeParams => { + let uuid = routeParams['uuid'] + this.videoService.getVideo(uuid).subscribe( + video => this.onVideoFetched(video), + + error => { + console.error(error) + this.videoNotFound = true + } + ) + }) + } + + ngOnDestroy () { + // Remove player if it exists + if (this.videoNotFound === false) { + videojs(this.playerElement).dispose() + } + + // Unsubscribe subscriptions + this.paramsSub.unsubscribe() + } + + setLike () { + if (this.isUserLoggedIn() === false) return + // Already liked this video + if (this.userRating === 'like') return + + this.videoService.setVideoLike(this.video.id) + .subscribe( + () => { + // Update the video like attribute + this.updateVideoRating(this.userRating, 'like') + this.userRating = 'like' + }, + + err => this.notificationsService.error('Error', err.message) + ) + } + + setDislike () { + if (this.isUserLoggedIn() === false) return + // Already disliked this video + if (this.userRating === 'dislike') return + + this.videoService.setVideoDislike(this.video.id) + .subscribe( + () => { + // Update the video dislike attribute + this.updateVideoRating(this.userRating, 'dislike') + this.userRating = 'dislike' + }, + + err => this.notificationsService.error('Error', err.message) + ) + } + + removeVideo (event: Event) { + event.preventDefault() + + this.confirmService.confirm('Do you really want to delete this video?', 'Delete').subscribe( + res => { + if (res === false) return + + this.videoService.removeVideo(this.video.id) + .subscribe( + status => { + this.notificationsService.success('Success', `Video ${this.video.name} deleted.`) + // Go back to the video-list. + this.router.navigate(['/videos/list']) + }, + + error => this.notificationsService.error('Error', error.text) + ) + } + ) + } + + blacklistVideo (event: Event) { + event.preventDefault() + + this.confirmService.confirm('Do you really want to blacklist this video ?', 'Blacklist').subscribe( + res => { + if (res === false) return + + this.videoService.blacklistVideo(this.video.id) + .subscribe( + status => { + this.notificationsService.success('Success', `Video ${this.video.name} had been blacklisted.`) + this.router.navigate(['/videos/list']) + }, + + error => this.notificationsService.error('Error', error.text) + ) + } + ) + } + + showReportModal (event: Event) { + event.preventDefault() + this.videoReportModal.show() + } + + showShareModal () { + this.videoShareModal.show() + } + + showMagnetUriModal (event: Event) { + event.preventDefault() + this.videoMagnetModal.show() + } + + isUserLoggedIn () { + return this.authService.isLoggedIn() + } + + canUserUpdateVideo () { + return this.video.isUpdatableBy(this.authService.getUser()) + } + + isVideoRemovable () { + return this.video.isRemovableBy(this.authService.getUser()) + } + + isVideoBlacklistable () { + return this.video.isBlackistableBy(this.authService.getUser()) + } + + private handleError (err: any) { + const errorMessage: string = typeof err === 'string' ? err : err.message + let message = '' + + if (errorMessage.indexOf('http error') !== -1) { + message = 'Cannot fetch video from server, maybe down.' + } else { + message = errorMessage + } + + this.notificationsService.error('Error', message) + } + + private checkUserRating () { + // Unlogged users do not have ratings + if (this.isUserLoggedIn() === false) return + + this.videoService.getUserVideoRating(this.video.id) + .subscribe( + ratingObject => { + if (ratingObject) { + this.userRating = ratingObject.rating + } + }, + + err => this.notificationsService.error('Error', err.message) + ) + } + + private onVideoFetched (video: Video) { + this.video = video + + let observable + if (this.video.isVideoNSFWForUser(this.authService.getUser())) { + observable = this.confirmService.confirm('This video is not safe for work. Are you sure you want to watch it?', 'NSFW') + } else { + observable = Observable.of(true) + } + + observable.subscribe( + res => { + if (res === false) { + return this.router.navigate([ '/videos/list' ]) + } + + this.playerElement = this.elementRef.nativeElement.querySelector('#video-container') + + const videojsOptions = { + controls: true, + autoplay: true, + plugins: { + peertube: { + videoFiles: this.video.files, + playerElement: this.playerElement, + autoplay: true, + peerTubeLink: false + } + } + } + + const self = this + videojs(this.playerElement, videojsOptions, function () { + self.player = this + this.on('customError', (event, data) => { + self.handleError(data.err) + }) + + this.on('torrentInfo', (event, data) => { + self.downloadSpeed = data.downloadSpeed + self.numPeers = data.numPeers + self.uploadSpeed = data.uploadSpeed + }) + }) + + this.setOpenGraphTags() + this.checkUserRating() + } + ) + } + + private updateVideoRating (oldRating: UserVideoRateType, newRating: VideoRateType) { + let likesToIncrement = 0 + let dislikesToIncrement = 0 + + if (oldRating) { + if (oldRating === 'like') likesToIncrement-- + if (oldRating === 'dislike') dislikesToIncrement-- + } + + if (newRating === 'like') likesToIncrement++ + if (newRating === 'dislike') dislikesToIncrement++ + + this.video.likes += likesToIncrement + this.video.dislikes += dislikesToIncrement + } + + private setOpenGraphTags () { + this.metaService.setTitle(this.video.name) + + this.metaService.setTag('og:type', 'video') + + this.metaService.setTag('og:title', this.video.name) + this.metaService.setTag('name', this.video.name) + + this.metaService.setTag('og:description', this.video.description) + this.metaService.setTag('description', this.video.description) + + this.metaService.setTag('og:image', this.video.previewPath) + + this.metaService.setTag('og:duration', this.video.duration.toString()) + + this.metaService.setTag('og:site_name', 'PeerTube') + + this.metaService.setTag('og:url', window.location.href) + this.metaService.setTag('url', window.location.href) + } +} diff --git a/client/src/app/videos/+video-watch/video-watch.module.ts b/client/src/app/videos/+video-watch/video-watch.module.ts new file mode 100644 index 000000000..5f20b171e --- /dev/null +++ b/client/src/app/videos/+video-watch/video-watch.module.ts @@ -0,0 +1,34 @@ +import { NgModule } from '@angular/core' + +import { VideoWatchRoutingModule } from './video-watch-routing.module' +import { VideoService } from '../shared' +import { SharedModule } from '../../shared' + +import { VideoWatchComponent } from './video-watch.component' +import { VideoReportComponent } from './video-report.component' +import { VideoShareComponent } from './video-share.component' +import { VideoMagnetComponent } from './video-magnet.component' + +@NgModule({ + imports: [ + VideoWatchRoutingModule, + SharedModule + ], + + declarations: [ + VideoWatchComponent, + + VideoMagnetComponent, + VideoShareComponent, + VideoReportComponent + ], + + exports: [ + VideoWatchComponent + ], + + providers: [ + VideoService + ] +}) +export class VideoWatchModule { } diff --git a/client/src/app/videos/index.ts b/client/src/app/videos/index.ts index 83edcc758..028a5854b 100644 --- a/client/src/app/videos/index.ts +++ b/client/src/app/videos/index.ts @@ -1,7 +1 @@ -export * from './shared' -export * from './video-edit' -export * from './video-list' -export * from './video-watch' -export * from './videos-routing.module' -export * from './videos.component' export * from './videos.module' diff --git a/client/src/app/videos/video-edit/index.ts b/client/src/app/videos/video-edit/index.ts deleted file mode 100644 index 3b4a9cb87..000000000 --- a/client/src/app/videos/video-edit/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './video-add.component' -export * from './video-update.component' diff --git a/client/src/app/videos/video-edit/video-add.component.html b/client/src/app/videos/video-edit/video-add.component.html deleted file mode 100644 index 698152ff9..000000000 --- a/client/src/app/videos/video-edit/video-add.component.html +++ /dev/null @@ -1,121 +0,0 @@ -
-
- -

Upload a video

- -
{{ error }}
- -
-
- - -
- {{ formErrors.name }} -
-
- -
- - -
- -
- - - -
- {{ formErrors.category }} -
-
- -
- - - -
- {{ formErrors.licence }} -
-
- -
- - - -
- {{ formErrors.language }} -
-
- -
- (press enter to add the tag) - -
- -
- -
- Select the video... - - -
-
- -
-
- {{ filename }} - -
-
- -
- {{ formErrors.videofile }} -
- -
- - -
- {{ formErrors.description }} -
-
- -
- - - - Server is processing the video - - -
- -
- -
-
-
-
diff --git a/client/src/app/videos/video-edit/video-add.component.ts b/client/src/app/videos/video-edit/video-add.component.ts deleted file mode 100644 index 21311b184..000000000 --- a/client/src/app/videos/video-edit/video-add.component.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { Component, OnInit, ViewChild } from '@angular/core' -import { FormBuilder, FormGroup } from '@angular/forms' -import { Router } from '@angular/router' - -import { NotificationsService } from 'angular2-notifications' - -import { - FormReactive, - VIDEO_NAME, - VIDEO_CATEGORY, - VIDEO_LICENCE, - VIDEO_LANGUAGE, - VIDEO_DESCRIPTION, - VIDEO_TAGS -} from '../../shared' -import { VideoService } from '../shared' -import { VideoCreate } from '../../../../../shared' -import { HttpEventType, HttpResponse } from '@angular/common/http' -import { VIDEO_FILE } from '../../shared/forms/form-validators/video' - -@Component({ - selector: 'my-videos-add', - styleUrls: [ './video-edit.component.scss' ], - templateUrl: './video-add.component.html' -}) - -export class VideoAddComponent extends FormReactive implements OnInit { - @ViewChild('videofileInput') videofileInput - - progressPercent = 0 - tags: string[] = [] - videoCategories = [] - videoLicences = [] - videoLanguages = [] - - tagValidators = VIDEO_TAGS.VALIDATORS - tagValidatorsMessages = VIDEO_TAGS.MESSAGES - - error: string - form: FormGroup - formErrors = { - name: '', - category: '', - licence: '', - language: '', - description: '', - videofile: '' - } - validationMessages = { - name: VIDEO_NAME.MESSAGES, - category: VIDEO_CATEGORY.MESSAGES, - licence: VIDEO_LICENCE.MESSAGES, - language: VIDEO_LANGUAGE.MESSAGES, - description: VIDEO_DESCRIPTION.MESSAGES, - videofile: VIDEO_FILE.MESSAGES - } - - constructor ( - private formBuilder: FormBuilder, - private router: Router, - private notificationsService: NotificationsService, - private videoService: VideoService - ) { - super() - } - - get filename () { - return this.form.value['videofile'] - } - - buildForm () { - this.form = this.formBuilder.group({ - name: [ '', VIDEO_NAME.VALIDATORS ], - nsfw: [ false ], - category: [ '', VIDEO_CATEGORY.VALIDATORS ], - licence: [ '', VIDEO_LICENCE.VALIDATORS ], - language: [ '', VIDEO_LANGUAGE.VALIDATORS ], - description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], - videofile: [ '', VIDEO_FILE.VALIDATORS ], - tags: [ '' ] - }) - - this.form.valueChanges.subscribe(data => this.onValueChanged(data)) - } - - ngOnInit () { - this.videoCategories = this.videoService.videoCategories - this.videoLicences = this.videoService.videoLicences - this.videoLanguages = this.videoService.videoLanguages - - this.buildForm() - } - - // The goal is to keep reactive form validation (required field) - // https://stackoverflow.com/a/44238894 - fileChange ($event) { - this.form.controls['videofile'].setValue($event.target.files[0].name) - } - - removeFile () { - this.videofileInput.nativeElement.value = '' - this.form.controls['videofile'].setValue('') - } - - checkForm () { - this.forceCheck() - - return this.form.valid - } - - upload () { - if (this.checkForm() === false) { - return - } - - const formValue: VideoCreate = this.form.value - - const name = formValue.name - const nsfw = formValue.nsfw - const category = formValue.category - const licence = formValue.licence - const language = formValue.language - const description = formValue.description - const tags = formValue.tags - const videofile = this.videofileInput.nativeElement.files[0] - - const formData = new FormData() - formData.append('name', name) - formData.append('category', '' + category) - formData.append('nsfw', '' + nsfw) - formData.append('licence', '' + licence) - formData.append('videofile', videofile) - - // Language is optional - if (language) { - formData.append('language', '' + language) - } - - formData.append('description', description) - - for (let i = 0; i < tags.length; i++) { - formData.append(`tags[${i}]`, tags[i]) - } - - this.videoService.uploadVideo(formData).subscribe( - event => { - if (event.type === HttpEventType.UploadProgress) { - this.progressPercent = Math.round(100 * event.loaded / event.total) - } else if (event instanceof HttpResponse) { - console.log('Video uploaded.') - this.notificationsService.success('Success', 'Video uploaded.') - - // Display all the videos once it's finished - this.router.navigate([ '/videos/list' ]) - } - }, - - err => { - // Reset progress - this.progressPercent = 0 - this.error = err.message - } - ) - } -} diff --git a/client/src/app/videos/video-edit/video-edit.component.scss b/client/src/app/videos/video-edit/video-edit.component.scss deleted file mode 100644 index 9ee0c520c..000000000 --- a/client/src/app/videos/video-edit/video-edit.component.scss +++ /dev/null @@ -1,56 +0,0 @@ -.btn-file { - position: relative; - overflow: hidden; - display: block; -} - -.btn-file input[type=file] { - position: absolute; - top: 0; - right: 0; - min-width: 100%; - min-height: 100%; - font-size: 100px; - text-align: right; - filter: alpha(opacity=0); - opacity: 0; - outline: none; - background: white; - cursor: inherit; - display: block; -} - -.form-group { - margin-bottom: 10px; -} - -div.tags { - height: 40px; - font-size: 20px; - margin-top: 20px; - - .tag { - margin-right: 10px; - - .remove { - cursor: pointer; - } - } -} - -div.file-to-upload { - height: 40px; - - .glyphicon-remove { - cursor: pointer; - } -} - -.little-information { - font-size: 0.8em; - font-style: italic; -} - -.label-tags { - margin-bottom: 0; -} diff --git a/client/src/app/videos/video-edit/video-update.component.html b/client/src/app/videos/video-edit/video-update.component.html deleted file mode 100644 index 7f4faf21b..000000000 --- a/client/src/app/videos/video-edit/video-update.component.html +++ /dev/null @@ -1,92 +0,0 @@ -
-
- -

Update {{ video?.name }}

- -
{{ error }}
- -
-
- - -
- {{ formErrors.name }} -
-
- -
- - -
- -
- - - -
- {{ formErrors.category }} -
-
- -
- - - -
- {{ formErrors.licence }} -
-
- -
- - - -
- {{ formErrors.language }} -
-
- -
- (press enter to add the tag) - -
- -
- - -
- {{ formErrors.description }} -
-
- -
- -
-
-
-
diff --git a/client/src/app/videos/video-edit/video-update.component.ts b/client/src/app/videos/video-edit/video-update.component.ts deleted file mode 100644 index 141ed3522..000000000 --- a/client/src/app/videos/video-edit/video-update.component.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { Component, ElementRef, OnInit } from '@angular/core' -import { FormBuilder, FormGroup } from '@angular/forms' -import { ActivatedRoute, Router } from '@angular/router' - -import { NotificationsService } from 'angular2-notifications' - -import { AuthService } from '../../core' -import { - FormReactive, - VIDEO_NAME, - VIDEO_CATEGORY, - VIDEO_LICENCE, - VIDEO_LANGUAGE, - VIDEO_DESCRIPTION, - VIDEO_TAGS -} from '../../shared' -import { Video, VideoService } from '../shared' - -@Component({ - selector: 'my-videos-update', - styleUrls: [ './video-edit.component.scss' ], - templateUrl: './video-update.component.html' -}) - -export class VideoUpdateComponent extends FormReactive implements OnInit { - tags: string[] = [] - videoCategories = [] - videoLicences = [] - videoLanguages = [] - video: Video - - tagValidators = VIDEO_TAGS.VALIDATORS - tagValidatorsMessages = VIDEO_TAGS.MESSAGES - - error: string = null - form: FormGroup - formErrors = { - name: '', - category: '', - licence: '', - language: '', - description: '' - } - validationMessages = { - name: VIDEO_NAME.MESSAGES, - category: VIDEO_CATEGORY.MESSAGES, - licence: VIDEO_LICENCE.MESSAGES, - language: VIDEO_LANGUAGE.MESSAGES, - description: VIDEO_DESCRIPTION.MESSAGES - } - - fileError = '' - - constructor ( - private authService: AuthService, - private elementRef: ElementRef, - private formBuilder: FormBuilder, - private route: ActivatedRoute, - private router: Router, - private notificationsService: NotificationsService, - private videoService: VideoService - ) { - super() - } - - buildForm () { - this.form = this.formBuilder.group({ - name: [ '', VIDEO_NAME.VALIDATORS ], - nsfw: [ false ], - category: [ '', VIDEO_CATEGORY.VALIDATORS ], - licence: [ '', VIDEO_LICENCE.VALIDATORS ], - language: [ '', VIDEO_LANGUAGE.VALIDATORS ], - description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], - tags: [ '' ] - }) - - this.form.valueChanges.subscribe(data => this.onValueChanged(data)) - } - - ngOnInit () { - this.buildForm() - - this.videoCategories = this.videoService.videoCategories - this.videoLicences = this.videoService.videoLicences - this.videoLanguages = this.videoService.videoLanguages - - const uuid: string = this.route.snapshot.params['uuid'] - this.videoService.getVideo(uuid) - .subscribe( - video => { - this.video = video - - this.hydrateFormFromVideo() - }, - - err => { - console.error(err) - this.error = 'Cannot fetch video.' - } - ) - } - - checkForm () { - this.forceCheck() - - return this.form.valid - } - - update () { - if (this.checkForm() === false) { - return - } - - this.video.patch(this.form.value) - - this.videoService.updateVideo(this.video) - .subscribe( - () => { - this.notificationsService.success('Success', 'Video updated.') - this.router.navigate([ '/videos/watch', this.video.uuid ]) - }, - - err => { - this.error = 'Cannot update the video.' - console.error(err) - } - ) - - } - - private hydrateFormFromVideo () { - this.form.patchValue(this.video.toJSON()) - } -} diff --git a/client/src/app/videos/video-watch/index.ts b/client/src/app/videos/video-watch/index.ts deleted file mode 100644 index 105872469..000000000 --- a/client/src/app/videos/video-watch/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './video-magnet.component' -export * from './video-share.component' -export * from './video-report.component' -export * from './video-watch.component' diff --git a/client/src/app/videos/video-watch/video-magnet.component.html b/client/src/app/videos/video-watch/video-magnet.component.html deleted file mode 100644 index 484280c45..000000000 --- a/client/src/app/videos/video-watch/video-magnet.component.html +++ /dev/null @@ -1,20 +0,0 @@ - diff --git a/client/src/app/videos/video-watch/video-magnet.component.ts b/client/src/app/videos/video-watch/video-magnet.component.ts deleted file mode 100644 index f9432e92c..000000000 --- a/client/src/app/videos/video-watch/video-magnet.component.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Component, Input, ViewChild } from '@angular/core' - -import { ModalDirective } from 'ngx-bootstrap/modal' - -import { Video } from '../shared' - -@Component({ - selector: 'my-video-magnet', - templateUrl: './video-magnet.component.html' -}) -export class VideoMagnetComponent { - @Input() video: Video = null - - @ViewChild('modal') modal: ModalDirective - - constructor () { - // empty - } - - show () { - this.modal.show() - } - - hide () { - this.modal.hide() - } -} diff --git a/client/src/app/videos/video-watch/video-report.component.html b/client/src/app/videos/video-watch/video-report.component.html deleted file mode 100644 index 741080ead..000000000 --- a/client/src/app/videos/video-watch/video-report.component.html +++ /dev/null @@ -1,38 +0,0 @@ - diff --git a/client/src/app/videos/video-watch/video-report.component.ts b/client/src/app/videos/video-watch/video-report.component.ts deleted file mode 100644 index d9c83a640..000000000 --- a/client/src/app/videos/video-watch/video-report.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, Input, OnInit, ViewChild } from '@angular/core' -import { FormBuilder, FormGroup } from '@angular/forms' - -import { ModalDirective } from 'ngx-bootstrap/modal' -import { NotificationsService } from 'angular2-notifications' - -import { FormReactive, VideoAbuseService, VIDEO_ABUSE_REASON } from '../../shared' -import { Video, VideoService } from '../shared' - -@Component({ - selector: 'my-video-report', - templateUrl: './video-report.component.html' -}) -export class VideoReportComponent extends FormReactive implements OnInit { - @Input() video: Video = null - - @ViewChild('modal') modal: ModalDirective - - error: string = null - form: FormGroup - formErrors = { - reason: '' - } - validationMessages = { - reason: VIDEO_ABUSE_REASON.MESSAGES - } - - constructor ( - private formBuilder: FormBuilder, - private videoAbuseService: VideoAbuseService, - private notificationsService: NotificationsService - ) { - super() - } - - ngOnInit () { - this.buildForm() - } - - buildForm () { - this.form = this.formBuilder.group({ - reason: [ '', VIDEO_ABUSE_REASON.VALIDATORS ] - }) - - this.form.valueChanges.subscribe(data => this.onValueChanged(data)) - } - - show () { - this.modal.show() - } - - hide () { - this.modal.hide() - } - - report () { - const reason = this.form.value['reason'] - - this.videoAbuseService.reportVideo(this.video.id, reason) - .subscribe( - () => { - this.notificationsService.success('Success', 'Video reported.') - this.hide() - }, - - err => this.notificationsService.error('Error', err.message) - ) - } -} diff --git a/client/src/app/videos/video-watch/video-share.component.html b/client/src/app/videos/video-watch/video-share.component.html deleted file mode 100644 index 88f59c063..000000000 --- a/client/src/app/videos/video-watch/video-share.component.html +++ /dev/null @@ -1,29 +0,0 @@ - diff --git a/client/src/app/videos/video-watch/video-share.component.ts b/client/src/app/videos/video-watch/video-share.component.ts deleted file mode 100644 index 133f93498..000000000 --- a/client/src/app/videos/video-watch/video-share.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Component, Input, ViewChild } from '@angular/core' - -import { ModalDirective } from 'ngx-bootstrap/modal' - -import { Video } from '../shared' - -@Component({ - selector: 'my-video-share', - templateUrl: './video-share.component.html' -}) -export class VideoShareComponent { - @Input() video: Video = null - - @ViewChild('modal') modal: ModalDirective - - constructor () { - // empty - } - - show () { - this.modal.show() - } - - hide () { - this.modal.hide() - } - - getVideoIframeCode () { - return '' - } - - getVideoUrl () { - return window.location.href - } - - notSecure () { - return window.location.protocol === 'http:' - } -} diff --git a/client/src/app/videos/video-watch/video-watch.component.html b/client/src/app/videos/video-watch/video-watch.component.html deleted file mode 100644 index 88863131a..000000000 --- a/client/src/app/videos/video-watch/video-watch.component.html +++ /dev/null @@ -1,184 +0,0 @@ -
-
- The video load seems to be abnormally long. - -
-
- -
- -
- -
- -
Video not found :'(
-
- - -
-
Download: {{ downloadSpeed | bytes }}/s
-
Upload: {{ uploadSpeed | bytes }}/s
-
Number of peers: {{ numPeers }}
-
- - -
-
-
- {{ video.name }} -
- -
- {{ video.views}} views -
-
- -
- - - - - - -
-
- - - - {{ video.likes }} - -
- -
- - - - {{ video.dislikes }} - -
-
-
- -
-
-
- Published on {{ video.createdAt | date:'short' }} -
- -
- {{ video.description }} -
-
- -
-
- - Category: - - - {{ video.categoryLabel }} - -
- -
- - Licence: - - - {{ video.licenceLabel }} - -
- -
- - Language: - - - {{ video.languageLabel }} - -
- -
- - Tags: - - - -
- -
-
-
- - - - - - diff --git a/client/src/app/videos/video-watch/video-watch.component.scss b/client/src/app/videos/video-watch/video-watch.component.scss deleted file mode 100644 index 69661747c..000000000 --- a/client/src/app/videos/video-watch/video-watch.component.scss +++ /dev/null @@ -1,245 +0,0 @@ -#video-container { - width: 100%; - height: 100%; -} - -#video-not-found { - height: 300px; - line-height: 300px; - margin-top: 50px; - text-align: center; - font-weight: bold; -} - -.embed-responsive { - height: 500px; - - @media screen and (max-width: 600px) { - height: 300px; - } -} - -#torrent-info { - font-size: 10px; - margin-top: 10px; - text-align: center; - - div { - min-width: 60px; - } -} - -#video-info { - .video-name-views { - font-weight: bold; - font-size: 18px; - height: $video-watch-title-height; - line-height: $video-watch-title-height; - - .video-name { - padding-left: $video-watch-info-padding-left; - } - - .video-views { - text-align: right; - // Keep a symmetry with the video name - padding-right: $video-watch-info-padding-left - } - - } - - .video-small-blocks { - height: $video-watch-info-height; - color: $video-watch-info-color; - border-color: $video-watch-border-color; - border-width: 1px 0px; - border-style: solid; - - .video-small-block { - height: $video-watch-info-height; - display: flex; - flex-direction: column; - justify-content: center; - text-align: center; - - a { - cursor: pointer; - transition: color 0.3s; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - &, &:hover { - color: inherit; - text-decoration:none; - } - - &:hover { - color: #000 !important; - } - - &:hover > .glyphicon { - opacity: 1 !important; - } - } - - .option .glyphicon { - font-size: 22px; - color: inherit; - opacity: 0.15; - margin-bottom: 10px; - transition: opacity 0.3s; - } - - .video-small-block-text { - font-size: 15px; - font-weight: bold; - } - } - - .video-small-block:not(:last-child) { - border-width: 0 1px 0 0; - border-color: $video-watch-border-color; - border-style: solid; - } - - .video-small-block-author, .video-small-block-more { - a.option { - display: block; - - .glyphicon { - display: block; - } - } - } - - .video-small-block-share, .video-small-block-more { - a.option { - display: block; - - .glyphicon { - display: block; - } - } - } - - .video-small-block-more .video-small-block-dropdown { - position: relative; - - .dropdown-item .glyphicon { - margin-right: 5px; - } - } - - .video-small-block-rating { - - .video-small-block-like { - margin-bottom: 10px; - } - - .video-small-block-text { - vertical-align: top; - } - - .glyphicon { - font-size: 18px; - margin: 0 10px 0 0; - opacity: 0.3; - } - - .interactive { - cursor: pointer; - transition: opacity, color 0.3s; - - &.activated, &:hover { - opacity: 1; - color: #000; - } - } - } - } - - .video-details { - margin-top: 30px; - - .video-details-date-description { - padding-left: $video-watch-info-padding-left; - - .video-details-date { - font-weight: bold; - margin-bottom: 30px; - } - } - - .video-details-attributes { - font-weight: bold; - font-size: 12px; - - .video-details-attribute-label { - color: $video-watch-info-color; - display: inline-block; - width: 60px; - margin-right: 5px; - } - } - - .video-details-tags { - display: inline-block; - - a { - display: inline-block; - margin-right: 3px; - font-size: 11px; - } - } - } - - @media screen and (max-width: 400px) { - .video-name-views { - font-size: 16px !important; - } - } - - @media screen and (max-width: 800px) { - .video-name-views { - .video-name { - padding-left: 5px; - padding-right: 0px; - } - - .video-views { - padding-left: 0px; - padding-right: 5px; - } - } - - .video-small-blocks { - a, .video-small-block-text { - font-size: 13px !important; - } - - .glyphicon { - font-size: 18px !important; - } - - .video-small-block-author { - padding-left: 10px; - } - } - - .video-details { - .video-details-date-description { - padding-left: 10px; - font-size: 13px !important; - } - - .video-details-attributes { - font-size: 11px !important; - - .video-details-attribute-label { - width: 50px; - } - } - } - } -} diff --git a/client/src/app/videos/video-watch/video-watch.component.ts b/client/src/app/videos/video-watch/video-watch.component.ts deleted file mode 100644 index db3e1cdd6..000000000 --- a/client/src/app/videos/video-watch/video-watch.component.ts +++ /dev/null @@ -1,299 +0,0 @@ -import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core' -import { ActivatedRoute, Router } from '@angular/router' -import { Observable } from 'rxjs/Observable' -import { Subscription } from 'rxjs/Subscription' - -import videojs from 'video.js' -import '../../../assets/player/peertube-videojs-plugin' - -import { MetaService } from '@ngx-meta/core' -import { NotificationsService } from 'angular2-notifications' - -import { AuthService, ConfirmService } from '../../core' -import { VideoMagnetComponent } from './video-magnet.component' -import { VideoShareComponent } from './video-share.component' -import { VideoReportComponent } from './video-report.component' -import { Video, VideoService } from '../shared' -import { WebTorrentService } from './webtorrent.service' -import { UserVideoRateType, VideoRateType } from '../../../../../shared' - -@Component({ - selector: 'my-video-watch', - templateUrl: './video-watch.component.html', - styleUrls: [ './video-watch.component.scss' ] -}) -export class VideoWatchComponent implements OnInit, OnDestroy { - @ViewChild('videoMagnetModal') videoMagnetModal: VideoMagnetComponent - @ViewChild('videoShareModal') videoShareModal: VideoShareComponent - @ViewChild('videoReportModal') videoReportModal: VideoReportComponent - - downloadSpeed: number - error = false - loading = false - numPeers: number - player: videojs.Player - playerElement: HTMLMediaElement - uploadSpeed: number - userRating: UserVideoRateType = null - video: Video = null - videoNotFound = false - - private paramsSub: Subscription - - constructor ( - private elementRef: ElementRef, - private route: ActivatedRoute, - private router: Router, - private videoService: VideoService, - private confirmService: ConfirmService, - private metaService: MetaService, - private authService: AuthService, - private notificationsService: NotificationsService - ) {} - - ngOnInit () { - this.paramsSub = this.route.params.subscribe(routeParams => { - let uuid = routeParams['uuid'] - this.videoService.getVideo(uuid).subscribe( - video => this.onVideoFetched(video), - - error => { - console.error(error) - this.videoNotFound = true - } - ) - }) - } - - ngOnDestroy () { - // Remove player if it exists - if (this.videoNotFound === false) { - videojs(this.playerElement).dispose() - } - - // Unsubscribe subscriptions - this.paramsSub.unsubscribe() - } - - setLike () { - if (this.isUserLoggedIn() === false) return - // Already liked this video - if (this.userRating === 'like') return - - this.videoService.setVideoLike(this.video.id) - .subscribe( - () => { - // Update the video like attribute - this.updateVideoRating(this.userRating, 'like') - this.userRating = 'like' - }, - - err => this.notificationsService.error('Error', err.message) - ) - } - - setDislike () { - if (this.isUserLoggedIn() === false) return - // Already disliked this video - if (this.userRating === 'dislike') return - - this.videoService.setVideoDislike(this.video.id) - .subscribe( - () => { - // Update the video dislike attribute - this.updateVideoRating(this.userRating, 'dislike') - this.userRating = 'dislike' - }, - - err => this.notificationsService.error('Error', err.message) - ) - } - - removeVideo (event: Event) { - event.preventDefault() - - this.confirmService.confirm('Do you really want to delete this video?', 'Delete').subscribe( - res => { - if (res === false) return - - this.videoService.removeVideo(this.video.id) - .subscribe( - status => { - this.notificationsService.success('Success', `Video ${this.video.name} deleted.`) - // Go back to the video-list. - this.router.navigate(['/videos/list']) - }, - - error => this.notificationsService.error('Error', error.text) - ) - } - ) - } - - blacklistVideo (event: Event) { - event.preventDefault() - - this.confirmService.confirm('Do you really want to blacklist this video ?', 'Blacklist').subscribe( - res => { - if (res === false) return - - this.videoService.blacklistVideo(this.video.id) - .subscribe( - status => { - this.notificationsService.success('Success', `Video ${this.video.name} had been blacklisted.`) - this.router.navigate(['/videos/list']) - }, - - error => this.notificationsService.error('Error', error.text) - ) - } - ) - } - - showReportModal (event: Event) { - event.preventDefault() - this.videoReportModal.show() - } - - showShareModal () { - this.videoShareModal.show() - } - - showMagnetUriModal (event: Event) { - event.preventDefault() - this.videoMagnetModal.show() - } - - isUserLoggedIn () { - return this.authService.isLoggedIn() - } - - canUserUpdateVideo () { - return this.video.isUpdatableBy(this.authService.getUser()) - } - - isVideoRemovable () { - return this.video.isRemovableBy(this.authService.getUser()) - } - - isVideoBlacklistable () { - return this.video.isBlackistableBy(this.authService.getUser()) - } - - private handleError (err: any) { - const errorMessage: string = typeof err === 'string' ? err : err.message - let message = '' - - if (errorMessage.indexOf('http error') !== -1) { - message = 'Cannot fetch video from server, maybe down.' - } else { - message = errorMessage - } - - this.notificationsService.error('Error', message) - } - - private checkUserRating () { - // Unlogged users do not have ratings - if (this.isUserLoggedIn() === false) return - - this.videoService.getUserVideoRating(this.video.id) - .subscribe( - ratingObject => { - if (ratingObject) { - this.userRating = ratingObject.rating - } - }, - - err => this.notificationsService.error('Error', err.message) - ) - } - - private onVideoFetched (video: Video) { - this.video = video - - let observable - if (this.video.isVideoNSFWForUser(this.authService.getUser())) { - observable = this.confirmService.confirm('This video is not safe for work. Are you sure you want to watch it?', 'NSFW') - } else { - observable = Observable.of(true) - } - - observable.subscribe( - res => { - if (res === false) { - return this.router.navigate([ '/videos/list' ]) - } - - this.playerElement = this.elementRef.nativeElement.querySelector('#video-container') - - const videojsOptions = { - controls: true, - autoplay: true, - plugins: { - peertube: { - videoFiles: this.video.files, - playerElement: this.playerElement, - autoplay: true, - peerTubeLink: false - } - } - } - - const self = this - videojs(this.playerElement, videojsOptions, function () { - self.player = this - this.on('customError', (event, data) => { - self.handleError(data.err) - }) - - this.on('torrentInfo', (event, data) => { - self.downloadSpeed = data.downloadSpeed - self.numPeers = data.numPeers - self.uploadSpeed = data.uploadSpeed - }) - }) - - this.setOpenGraphTags() - this.checkUserRating() - } - ) - } - - private updateVideoRating (oldRating: UserVideoRateType, newRating: VideoRateType) { - let likesToIncrement = 0 - let dislikesToIncrement = 0 - - if (oldRating) { - if (oldRating === 'like') likesToIncrement-- - if (oldRating === 'dislike') dislikesToIncrement-- - } - - if (newRating === 'like') likesToIncrement++ - if (newRating === 'dislike') dislikesToIncrement++ - - this.video.likes += likesToIncrement - this.video.dislikes += dislikesToIncrement - } - - private setOpenGraphTags () { - this.metaService.setTitle(this.video.name) - - this.metaService.setTag('og:type', 'video') - - this.metaService.setTag('og:title', this.video.name) - this.metaService.setTag('name', this.video.name) - - this.metaService.setTag('og:description', this.video.description) - this.metaService.setTag('description', this.video.description) - - this.metaService.setTag('og:image', this.video.previewPath) - - this.metaService.setTag('og:duration', this.video.duration.toString()) - - this.metaService.setTag('og:site_name', 'PeerTube') - - this.metaService.setTag('og:url', window.location.href) - this.metaService.setTag('url', window.location.href) - } -} diff --git a/client/src/app/videos/videos-routing.module.ts b/client/src/app/videos/videos-routing.module.ts index 715671ba7..225b6b018 100644 --- a/client/src/app/videos/videos-routing.module.ts +++ b/client/src/app/videos/videos-routing.module.ts @@ -3,10 +3,8 @@ import { RouterModule, Routes } from '@angular/router' import { MetaGuard } from '@ngx-meta/core' -import { VideoAddComponent, VideoUpdateComponent } from './video-edit' import { VideoListComponent } from './video-list' import { VideosComponent } from './videos.component' -import { VideoWatchComponent } from './video-watch' const videosRoutes: Routes = [ { @@ -25,7 +23,7 @@ const videosRoutes: Routes = [ }, { path: 'add', - component: VideoAddComponent, + loadChildren: 'app/videos/+video-edit#VideoAddModule', data: { meta: { title: 'Add a video' @@ -34,7 +32,7 @@ const videosRoutes: Routes = [ }, { path: 'edit/:uuid', - component: VideoUpdateComponent, + loadChildren: 'app/videos/+video-edit#VideoUpdateModule', data: { meta: { title: 'Edit a video' @@ -47,7 +45,10 @@ const videosRoutes: Routes = [ }, { path: 'watch/:uuid', - component: VideoWatchComponent + loadChildren: 'app/videos/+video-watch#VideoWatchModule', + data: { + preload: 3000 + } } ] } diff --git a/client/src/app/videos/videos.component.ts b/client/src/app/videos/videos.component.ts index 972c2221f..26d9d28d4 100644 --- a/client/src/app/videos/videos.component.ts +++ b/client/src/app/videos/videos.component.ts @@ -1,8 +1,16 @@ -import { Component } from '@angular/core' +import { Component, OnInit } from '@angular/core' + +import { VideoService } from './shared' @Component({ template: '' }) +export class VideosComponent implements OnInit { + constructor(private videoService: VideoService) {} -export class VideosComponent { + ngOnInit () { + this.videoService.loadVideoCategories() + this.videoService.loadVideoLicences() + this.videoService.loadVideoLanguages() + } } diff --git a/client/src/app/videos/videos.module.ts b/client/src/app/videos/videos.module.ts index bc86118cc..3a0c3feac 100644 --- a/client/src/app/videos/videos.module.ts +++ b/client/src/app/videos/videos.module.ts @@ -1,24 +1,13 @@ import { NgModule } from '@angular/core' -import { TagInputModule } from 'ngx-chips' - import { VideosRoutingModule } from './videos-routing.module' import { VideosComponent } from './videos.component' -import { VideoAddComponent, VideoUpdateComponent } from './video-edit' import { LoaderComponent, VideoListComponent, VideoMiniatureComponent, VideoSortComponent } from './video-list' -import { - VideoWatchComponent, - VideoMagnetComponent, - VideoReportComponent, - VideoShareComponent -} from './video-watch' import { VideoService } from './shared' import { SharedModule } from '../shared' @NgModule({ imports: [ - TagInputModule, - VideosRoutingModule, SharedModule ], @@ -26,18 +15,10 @@ import { SharedModule } from '../shared' declarations: [ VideosComponent, - VideoAddComponent, - VideoUpdateComponent, - VideoListComponent, VideoMiniatureComponent, VideoSortComponent, - VideoWatchComponent, - VideoMagnetComponent, - VideoShareComponent, - VideoReportComponent, - LoaderComponent ], -- cgit v1.2.3