import { Component, OnInit, ViewContainerRef } from '@angular/core';
import { Router } from '@angular/router';
-import { AuthService } from './core';
+import { AuthService, ConfigService } from './core';
import { VideoService } from './videos';
import { UserService } from './shared';
constructor(
private router: Router,
private authService: AuthService,
+ private configService: ConfigService,
private userService: UserService,
private videoService: VideoService,
viewContainerRef: ViewContainerRef
this.userService.checkTokenValidity();
}
+ this.configService.loadConfig();
this.videoService.loadVideoCategories();
this.videoService.loadVideoLicences();
}
private static KEYS = {
ID: 'id',
ROLE: 'role',
- USERNAME: 'username'
+ USERNAME: 'username',
+ DISPLAY_NSFW: 'display_nsfw'
};
tokens: Tokens;
{
id: parseInt(localStorage.getItem(this.KEYS.ID)),
username: localStorage.getItem(this.KEYS.USERNAME),
- role: localStorage.getItem(this.KEYS.ROLE)
+ role: localStorage.getItem(this.KEYS.ROLE),
+ displayNSFW: localStorage.getItem(this.KEYS.DISPLAY_NSFW) === 'true'
},
Tokens.load()
);
localStorage.removeItem(this.KEYS.USERNAME);
localStorage.removeItem(this.KEYS.ID);
localStorage.removeItem(this.KEYS.ROLE);
+ localStorage.removeItem(this.KEYS.DISPLAY_NSFW);
Tokens.flush();
}
- constructor(userHash: { id: number, username: string, role: string }, hashTokens: any) {
+ constructor(userHash: {
+ id: number,
+ username: string,
+ role: string,
+ displayNSFW: boolean
+ }, hashTokens: any) {
super(userHash);
this.tokens = new Tokens(hashTokens);
}
localStorage.setItem(AuthUser.KEYS.ID, this.id.toString());
localStorage.setItem(AuthUser.KEYS.USERNAME, this.username);
localStorage.setItem(AuthUser.KEYS.ROLE, this.role);
+ localStorage.setItem(AuthUser.KEYS.DISPLAY_NSFW, JSON.stringify(this.displayNSFW);
this.tokens.save();
}
}
--- /dev/null
+import { Injectable } from '@angular/core';
+import { Http } from '@angular/http';
+
+import { RestExtractor } from '../../shared/rest';
+
+@Injectable()
+export class ConfigService {
+ private static BASE_CONFIG_URL = '/api/v1/config/';
+
+ private config: {
+ signup: {
+ enabled: boolean
+ }
+ } = {
+ signup: {
+ enabled: false
+ }
+ };
+
+ constructor(
+ private http: Http,
+ private restExtractor: RestExtractor,
+ ) {}
+
+ loadConfig() {
+ this.http.get(ConfigService.BASE_CONFIG_URL)
+ .map(this.restExtractor.extractDataGet)
+ .subscribe(data => {
+ this.config = data;
+ });
+ }
+
+ getConfig() {
+ return this.config;
+ }
+}
--- /dev/null
+export * from './config.service';
import { ModalModule } from 'ng2-bootstrap/modal';
import { AuthService } from './auth';
+import { ConfigService } from './config';
import { ConfirmComponent, ConfirmService } from './confirm';
import { MenuComponent, MenuAdminComponent } from './menu';
import { throwIfAlreadyLoaded } from './module-import-guard';
providers: [
AuthService,
- ConfirmService
+ ConfirmService,
+ ConfigService
]
})
export class CoreModule {
export * from './auth';
+export * from './config';
export * from './confirm';
export * from './menu';
export * from './core.module'
id: number;
username: string;
role: string;
+ displayNSFW: boolean;
createdAt: Date;
- constructor(hash: { id: number, username: string, role: string, createdAt?: Date }) {
+ constructor(hash: {
+ id: number,
+ username: string,
+ role: string,
+ displayNSFW?: boolean,
+ createdAt?: Date,
+ }) {
this.id = hash.id;
this.username = hash.username;
this.role = hash.role;
+ this.displayNSFW = hash.displayNSFW;
if (hash.createdAt) {
this.createdAt = hash.createdAt;
+import { User } from '../../shared';
+
export class Video {
author: string;
by: string;
views: number;
likes: number;
dislikes: number;
+ nsfw: boolean;
private static createByString(author: string, podHost: string) {
return author + '@' + podHost;
views: number,
likes: number,
dislikes: number,
+ nsfw: boolean
}) {
this.author = hash.author;
this.createdAt = new Date(hash.createdAt);
this.views = hash.views;
this.likes = hash.likes;
this.dislikes = hash.dislikes;
+ this.nsfw = hash.nsfw;
this.by = Video.createByString(hash.author, hash.podHost);
}
- isRemovableBy(user) {
+ isRemovableBy(user: User) {
return this.isLocal === true && user && this.author === user.username;
}
+
+ isVideoNSFWForUser(user: User) {
+ // If the video is NSFW and the user is not logged in, or the user does not want to display NSFW videos...
+ return (this.nsfw && (!user || user.displayNSFW === false));
+ }
}
</div>
</div>
+ <div class="form-group">
+ <label for="nsfw">NSFW</label>
+ <input
+ type="checkbox" id="nsfw"
+ formControlName="nsfw"
+ >
+ </div>
+
<div class="form-group">
<label for="category">Category</label>
<select class="form-control" id="category" formControlName="category">
buildForm() {
this.form = this.formBuilder.group({
name: [ '', VIDEO_NAME.VALIDATORS ],
+ nsfw: [ false ],
category: [ '', VIDEO_CATEGORY.VALIDATORS ],
licence: [ '', VIDEO_LICENCE.VALIDATORS ],
description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
this.uploader.onBuildItemForm = (item, form) => {
const name = this.form.value['name'];
+ const nsfw = this.form.value['nsfw'];
const category = this.form.value['category'];
const licence = this.form.value['licence'];
const description = this.form.value['description'];
form.append('name', name);
form.append('category', category);
+ form.append('nsfw', nsfw);
form.append('licence', licence);
form.append('description', description);
[routerLink]="['/videos/watch', video.id]" [attr.title]="video.description"
class="video-miniature-thumbnail"
>
- <img [attr.src]="video.thumbnailPath" alt="video thumbnail" />
+ <img *ngIf="isVideoNSFWForThisUser() === false" [attr.src]="video.thumbnailPath" alt="video thumbnail" />
+ <div *ngIf="isVideoNSFWForThisUser()" class="thumbnail-nsfw">
+ NSFW
+ </div>
+
<span class="video-miniature-duration">{{ video.duration }}</span>
</a>
<span
<div class="video-miniature-informations">
<span class="video-miniature-name-tags">
- <a [routerLink]="['/videos/watch', video.id]" [attr.title]="video.name" class="video-miniature-name">{{ video.name }}</a>
+ <a [routerLink]="['/videos/watch', video.id]" [attr.title]="getVideoName()" class="video-miniature-name">{{ getVideoName() }}</a>
<div class="video-miniature-tags">
<span *ngFor="let tag of video.tags" class="video-miniature-tag">
display: inline-block;
position: relative;
+ &:hover {
+ text-decoration: none !important;
+ }
+
+ .thumbnail-nsfw {
+ background-color: #000;
+ color: #fff;
+ text-align: center;
+ font-size: 30px;
+ line-height: 110px;
+
+ width: 200px;
+ height: 110px;
+ }
+
.video-miniature-duration {
position: absolute;
right: 5px;
import { NotificationsService } from 'angular2-notifications';
-import { ConfirmService } from '../../core';
+import { ConfirmService, ConfigService } from '../../core';
import { SortField, Video, VideoService } from '../shared';
import { User } from '../../shared';
constructor(
private notificationsService: NotificationsService,
private confirmService: ConfirmService,
+ private configService: ConfigService,
private videoService: VideoService
) {}
return this.hovering && this.video.isRemovableBy(this.user);
}
+ getVideoName() {
+ if (this.isVideoNSFWForThisUser())
+ return 'NSFW';
+
+ return this.video.name;
+ }
+
onBlur() {
this.hovering = false;
}
}
);
}
+
+ isVideoNSFWForThisUser() {
+ return this.video.isVideoNSFWForUser(this.user);
+ }
}
import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core';
-import { ActivatedRoute } from '@angular/router';
+import { ActivatedRoute, Router } from '@angular/router';
+import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import * as videojs from 'video.js';
import { MetaService } from '@nglibs/meta';
import { NotificationsService } from 'angular2-notifications';
-import { AuthService } from '../../core';
+import { AuthService, ConfirmService } from '../../core';
import { VideoMagnetComponent } from './video-magnet.component';
import { VideoShareComponent } from './video-share.component';
import { VideoReportComponent } from './video-report.component';
private elementRef: ElementRef,
private ngZone: NgZone,
private route: ActivatedRoute,
+ private router: Router,
private videoService: VideoService,
+ private confirmService: ConfirmService,
private metaService: MetaService,
private webTorrentService: WebTorrentService,
private authService: AuthService,
this.paramsSub = this.route.params.subscribe(routeParams => {
let id = routeParams['id'];
this.videoService.getVideo(id).subscribe(
- video => {
- this.video = video;
- this.setOpenGraphTags();
- this.loadVideo();
- this.checkUserRating();
- },
- error => {
- this.videoNotFound = true;
- }
+ video => this.onVideoFetched(video),
+
+ error => this.videoNotFound = true
);
});
window.clearInterval(this.torrentInfosInterval);
window.clearTimeout(this.errorTimer);
- if (this.video !== null) {
+ if (this.video !== null && this.webTorrentService.has(this.video.magnetUri)) {
this.webTorrentService.remove(this.video.magnetUri);
}
);
}
+ 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.setOpenGraphTags();
+ this.loadVideo();
+ this.checkUserRating();
+ }
+ );
+ }
+
private updateVideoRating(oldRating: RateType, newRating: RateType) {
let likesToIncrement = 0;
let dislikesToIncrement = 0;
remove(magnetUri: string) {
return this.client.remove(magnetUri);
}
+
+ has(magnetUri: string) {
+ return this.client.get(magnetUri) !== null;
+ }
}