aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/videos/shared
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/videos/shared')
-rw-r--r--client/src/app/videos/shared/index.ts7
-rw-r--r--client/src/app/videos/shared/sort-field.type.ts5
-rw-r--r--client/src/app/videos/shared/video-description.component.html9
-rw-r--r--client/src/app/videos/shared/video-description.component.scss15
-rw-r--r--client/src/app/videos/shared/video-description.component.ts68
-rw-r--r--client/src/app/videos/shared/video-details.model.ts84
-rw-r--r--client/src/app/videos/shared/video-edit.model.ts50
-rw-r--r--client/src/app/videos/shared/video-pagination.model.ts5
-rw-r--r--client/src/app/videos/shared/video.model.ts90
-rw-r--r--client/src/app/videos/shared/video.service.ts176
10 files changed, 0 insertions, 509 deletions
diff --git a/client/src/app/videos/shared/index.ts b/client/src/app/videos/shared/index.ts
index 3f1458088..7a66944b9 100644
--- a/client/src/app/videos/shared/index.ts
+++ b/client/src/app/videos/shared/index.ts
@@ -1,8 +1 @@
1export * from './sort-field.type'
2export * from './markdown.service' export * from './markdown.service'
3export * from './video.model'
4export * from './video-details.model'
5export * from './video-edit.model'
6export * from './video.service'
7export * from './video-description.component'
8export * from './video-pagination.model'
diff --git a/client/src/app/videos/shared/sort-field.type.ts b/client/src/app/videos/shared/sort-field.type.ts
deleted file mode 100644
index 776f360f8..000000000
--- a/client/src/app/videos/shared/sort-field.type.ts
+++ /dev/null
@@ -1,5 +0,0 @@
1export type SortField = 'name' | '-name'
2 | 'duration' | '-duration'
3 | 'createdAt' | '-createdAt'
4 | 'views' | '-views'
5 | 'likes' | '-likes'
diff --git a/client/src/app/videos/shared/video-description.component.html b/client/src/app/videos/shared/video-description.component.html
deleted file mode 100644
index 7a228857c..000000000
--- a/client/src/app/videos/shared/video-description.component.html
+++ /dev/null
@@ -1,9 +0,0 @@
1<textarea
2 [(ngModel)]="description" (ngModelChange)="onModelChange()"
3 id="description" class="form-control" placeholder="My super video">
4</textarea>
5
6<tabset #staticTabs class="previews">
7 <tab heading="Truncated description preview" [innerHTML]="truncatedDescriptionHTML"></tab>
8 <tab heading="Complete description preview" [innerHTML]="descriptionHTML"></tab>
9</tabset>
diff --git a/client/src/app/videos/shared/video-description.component.scss b/client/src/app/videos/shared/video-description.component.scss
deleted file mode 100644
index d8d73e846..000000000
--- a/client/src/app/videos/shared/video-description.component.scss
+++ /dev/null
@@ -1,15 +0,0 @@
1textarea {
2 height: 150px;
3}
4
5.previews /deep/ {
6 .nav {
7 margin-top: 10px;
8 font-size: 0.9em;
9 }
10
11 .tab-content {
12 min-height: 75px;
13 padding: 5px;
14 }
15}
diff --git a/client/src/app/videos/shared/video-description.component.ts b/client/src/app/videos/shared/video-description.component.ts
deleted file mode 100644
index d9ffb7800..000000000
--- a/client/src/app/videos/shared/video-description.component.ts
+++ /dev/null
@@ -1,68 +0,0 @@
1import { Component, forwardRef, Input, OnInit } from '@angular/core'
2import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
3import { Subject } from 'rxjs/Subject'
4import 'rxjs/add/operator/debounceTime'
5import 'rxjs/add/operator/distinctUntilChanged'
6
7import { truncate } from 'lodash'
8
9import { MarkdownService } from './markdown.service'
10
11@Component({
12 selector: 'my-video-description',
13 templateUrl: './video-description.component.html',
14 styleUrls: [ './video-description.component.scss' ],
15 providers: [
16 {
17 provide: NG_VALUE_ACCESSOR,
18 useExisting: forwardRef(() => VideoDescriptionComponent),
19 multi: true
20 }
21 ]
22})
23
24export class VideoDescriptionComponent implements ControlValueAccessor, OnInit {
25 @Input() description = ''
26 truncatedDescriptionHTML = ''
27 descriptionHTML = ''
28
29 private descriptionChanged = new Subject<string>()
30
31 constructor (private markdownService: MarkdownService) {}
32
33 ngOnInit () {
34 this.descriptionChanged
35 .debounceTime(150)
36 .distinctUntilChanged()
37 .subscribe(() => this.updateDescriptionPreviews())
38
39 this.descriptionChanged.next(this.description)
40 }
41
42 propagateChange = (_: any) => { /* empty */ }
43
44 writeValue (description: string) {
45 this.description = description
46
47 this.descriptionChanged.next(this.description)
48 }
49
50 registerOnChange (fn: (_: any) => void) {
51 this.propagateChange = fn
52 }
53
54 registerOnTouched () {
55 // Unused
56 }
57
58 onModelChange () {
59 this.propagateChange(this.description)
60
61 this.descriptionChanged.next(this.description)
62 }
63
64 private updateDescriptionPreviews () {
65 this.truncatedDescriptionHTML = this.markdownService.markdownToHTML(truncate(this.description, { length: 250 }))
66 this.descriptionHTML = this.markdownService.markdownToHTML(this.description)
67 }
68}
diff --git a/client/src/app/videos/shared/video-details.model.ts b/client/src/app/videos/shared/video-details.model.ts
deleted file mode 100644
index 64cb4f847..000000000
--- a/client/src/app/videos/shared/video-details.model.ts
+++ /dev/null
@@ -1,84 +0,0 @@
1import { Video } from './video.model'
2import { AuthUser } from '../../core'
3import {
4 VideoDetails as VideoDetailsServerModel,
5 VideoFile,
6 VideoChannel,
7 VideoResolution,
8 UserRight,
9 VideoPrivacy
10} from '../../../../../shared'
11
12export class VideoDetails extends Video implements VideoDetailsServerModel {
13 account: string
14 by: string
15 createdAt: Date
16 updatedAt: Date
17 categoryLabel: string
18 category: number
19 licenceLabel: string
20 licence: number
21 languageLabel: string
22 language: number
23 description: string
24 duration: number
25 durationLabel: string
26 id: number
27 uuid: string
28 isLocal: boolean
29 name: string
30 serverHost: string
31 tags: string[]
32 thumbnailPath: string
33 thumbnailUrl: string
34 previewPath: string
35 previewUrl: string
36 embedPath: string
37 embedUrl: string
38 views: number
39 likes: number
40 dislikes: number
41 nsfw: boolean
42 descriptionPath: string
43 files: VideoFile[]
44 channel: VideoChannel
45 privacy: VideoPrivacy
46 privacyLabel: string
47
48 constructor (hash: VideoDetailsServerModel) {
49 super(hash)
50
51 this.privacy = hash.privacy
52 this.privacyLabel = hash.privacyLabel
53 this.descriptionPath = hash.descriptionPath
54 this.files = hash.files
55 this.channel = hash.channel
56 }
57
58 getAppropriateMagnetUri (actualDownloadSpeed = 0) {
59 if (this.files === undefined || this.files.length === 0) return ''
60 if (this.files.length === 1) return this.files[0].magnetUri
61
62 // Find first video that is good for our download speed (remember they are sorted)
63 let betterResolutionFile = this.files.find(f => actualDownloadSpeed > (f.size / this.duration))
64
65 // If the download speed is too bad, return the lowest resolution we have
66 if (betterResolutionFile === undefined) {
67 betterResolutionFile = this.files.find(f => f.resolution === VideoResolution.H_240P)
68 }
69
70 return betterResolutionFile.magnetUri
71 }
72
73 isRemovableBy (user: AuthUser) {
74 return user && this.isLocal === true && (this.account === user.username || user.hasRight(UserRight.REMOVE_ANY_VIDEO))
75 }
76
77 isBlackistableBy (user: AuthUser) {
78 return user && user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) === true && this.isLocal === false
79 }
80
81 isUpdatableBy (user: AuthUser) {
82 return user && this.isLocal === true && user.username === this.account
83 }
84}
diff --git a/client/src/app/videos/shared/video-edit.model.ts b/client/src/app/videos/shared/video-edit.model.ts
deleted file mode 100644
index 88d23a59f..000000000
--- a/client/src/app/videos/shared/video-edit.model.ts
+++ /dev/null
@@ -1,50 +0,0 @@
1import { VideoDetails } from './video-details.model'
2import { VideoPrivacy } from '../../../../../shared/models/videos/video-privacy.enum'
3
4export class VideoEdit {
5 category: number
6 licence: number
7 language: number
8 description: string
9 name: string
10 tags: string[]
11 nsfw: boolean
12 channel: number
13 privacy: VideoPrivacy
14 uuid?: string
15 id?: number
16
17 constructor (videoDetails: VideoDetails) {
18 this.id = videoDetails.id
19 this.uuid = videoDetails.uuid
20 this.category = videoDetails.category
21 this.licence = videoDetails.licence
22 this.language = videoDetails.language
23 this.description = videoDetails.description
24 this.name = videoDetails.name
25 this.tags = videoDetails.tags
26 this.nsfw = videoDetails.nsfw
27 this.channel = videoDetails.channel.id
28 this.privacy = videoDetails.privacy
29 }
30
31 patch (values: Object) {
32 Object.keys(values).forEach((key) => {
33 this[key] = values[key]
34 })
35 }
36
37 toJSON () {
38 return {
39 category: this.category,
40 licence: this.licence,
41 language: this.language,
42 description: this.description,
43 name: this.name,
44 tags: this.tags,
45 nsfw: this.nsfw,
46 channel: this.channel,
47 privacy: this.privacy
48 }
49 }
50}
diff --git a/client/src/app/videos/shared/video-pagination.model.ts b/client/src/app/videos/shared/video-pagination.model.ts
deleted file mode 100644
index 9e71769cb..000000000
--- a/client/src/app/videos/shared/video-pagination.model.ts
+++ /dev/null
@@ -1,5 +0,0 @@
1export interface VideoPagination {
2 currentPage: number
3 itemsPerPage: number
4 totalItems: number
5}
diff --git a/client/src/app/videos/shared/video.model.ts b/client/src/app/videos/shared/video.model.ts
deleted file mode 100644
index 0dd41d71b..000000000
--- a/client/src/app/videos/shared/video.model.ts
+++ /dev/null
@@ -1,90 +0,0 @@
1import { Video as VideoServerModel } from '../../../../../shared'
2import { User } from '../../shared'
3
4export class Video implements VideoServerModel {
5 account: string
6 by: string
7 createdAt: Date
8 updatedAt: Date
9 categoryLabel: string
10 category: number
11 licenceLabel: string
12 licence: number
13 languageLabel: string
14 language: number
15 description: string
16 duration: number
17 durationLabel: string
18 id: number
19 uuid: string
20 isLocal: boolean
21 name: string
22 serverHost: string
23 tags: string[]
24 thumbnailPath: string
25 thumbnailUrl: string
26 previewPath: string
27 previewUrl: string
28 embedPath: string
29 embedUrl: string
30 views: number
31 likes: number
32 dislikes: number
33 nsfw: boolean
34
35 private static createByString (account: string, serverHost: string) {
36 return account + '@' + serverHost
37 }
38
39 private static createDurationString (duration: number) {
40 const minutes = Math.floor(duration / 60)
41 const seconds = duration % 60
42 const minutesPadding = minutes >= 10 ? '' : '0'
43 const secondsPadding = seconds >= 10 ? '' : '0'
44
45 return minutesPadding + minutes.toString() + ':' + secondsPadding + seconds.toString()
46 }
47
48 constructor (hash: VideoServerModel) {
49 let absoluteAPIUrl = API_URL
50 if (!absoluteAPIUrl) {
51 // The API is on the same domain
52 absoluteAPIUrl = window.location.origin
53 }
54
55 this.account = hash.account
56 this.createdAt = new Date(hash.createdAt.toString())
57 this.categoryLabel = hash.categoryLabel
58 this.category = hash.category
59 this.licenceLabel = hash.licenceLabel
60 this.licence = hash.licence
61 this.languageLabel = hash.languageLabel
62 this.language = hash.language
63 this.description = hash.description
64 this.duration = hash.duration
65 this.durationLabel = Video.createDurationString(hash.duration)
66 this.id = hash.id
67 this.uuid = hash.uuid
68 this.isLocal = hash.isLocal
69 this.name = hash.name
70 this.serverHost = hash.serverHost
71 this.tags = hash.tags
72 this.thumbnailPath = hash.thumbnailPath
73 this.thumbnailUrl = absoluteAPIUrl + hash.thumbnailPath
74 this.previewPath = hash.previewPath
75 this.previewUrl = absoluteAPIUrl + hash.previewPath
76 this.embedPath = hash.embedPath
77 this.embedUrl = absoluteAPIUrl + hash.embedPath
78 this.views = hash.views
79 this.likes = hash.likes
80 this.dislikes = hash.dislikes
81 this.nsfw = hash.nsfw
82
83 this.by = Video.createByString(hash.account, hash.serverHost)
84 }
85
86 isVideoNSFWForUser (user: User) {
87 // If the video is NSFW and the user is not logged in, or the user does not want to display NSFW videos...
88 return (this.nsfw && (!user || user.displayNSFW === false))
89 }
90}
diff --git a/client/src/app/videos/shared/video.service.ts b/client/src/app/videos/shared/video.service.ts
deleted file mode 100644
index 5d25a26d4..000000000
--- a/client/src/app/videos/shared/video.service.ts
+++ /dev/null
@@ -1,176 +0,0 @@
1import { Injectable } from '@angular/core'
2import { Observable } from 'rxjs/Observable'
3import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http'
4import 'rxjs/add/operator/catch'
5import 'rxjs/add/operator/map'
6
7import { SortField } from './sort-field.type'
8import {
9 RestExtractor,
10 RestService,
11 UserService,
12 Search
13} from '../../shared'
14import { Video } from './video.model'
15import { VideoDetails } from './video-details.model'
16import { VideoEdit } from './video-edit.model'
17import { VideoPagination } from './video-pagination.model'
18import {
19 UserVideoRate,
20 VideoRateType,
21 VideoUpdate,
22 UserVideoRateUpdate,
23 Video as VideoServerModel,
24 VideoDetails as VideoDetailsServerModel,
25 ResultList
26} from '../../../../../shared'
27
28@Injectable()
29export class VideoService {
30 private static BASE_VIDEO_URL = API_URL + '/api/v1/videos/'
31
32 constructor (
33 private authHttp: HttpClient,
34 private restExtractor: RestExtractor,
35 private restService: RestService
36 ) {}
37
38 getVideo (uuid: string): Observable<VideoDetails> {
39 return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
40 .map(videoHash => new VideoDetails(videoHash))
41 .catch((res) => this.restExtractor.handleError(res))
42 }
43
44 viewVideo (uuid: string): Observable<VideoDetails> {
45 return this.authHttp.post(VideoService.BASE_VIDEO_URL + uuid + '/views', {})
46 .map(this.restExtractor.extractDataBool)
47 .catch(this.restExtractor.handleError)
48 }
49
50 updateVideo (video: VideoEdit) {
51 const language = video.language ? video.language : null
52
53 const body: VideoUpdate = {
54 name: video.name,
55 category: video.category,
56 licence: video.licence,
57 language,
58 description: video.description,
59 privacy: video.privacy,
60 tags: video.tags,
61 nsfw: video.nsfw
62 }
63
64 return this.authHttp.put(VideoService.BASE_VIDEO_URL + video.id, body)
65 .map(this.restExtractor.extractDataBool)
66 .catch(this.restExtractor.handleError)
67 }
68
69 uploadVideo (video: FormData) {
70 const req = new HttpRequest('POST', VideoService.BASE_VIDEO_URL + 'upload', video, { reportProgress: true })
71
72 return this.authHttp
73 .request(req)
74 .catch(this.restExtractor.handleError)
75 }
76
77 getMyVideos (videoPagination: VideoPagination, sort: SortField): Observable<{ videos: Video[], totalVideos: number}> {
78 const pagination = this.videoPaginationToRestPagination(videoPagination)
79
80 let params = new HttpParams()
81 params = this.restService.addRestGetParams(params, pagination, sort)
82
83 return this.authHttp.get(UserService.BASE_USERS_URL + '/me/videos', { params })
84 .map(this.extractVideos)
85 .catch((res) => this.restExtractor.handleError(res))
86 }
87
88 getVideos (videoPagination: VideoPagination, sort: SortField): Observable<{ videos: Video[], totalVideos: number}> {
89 const pagination = this.videoPaginationToRestPagination(videoPagination)
90
91 let params = new HttpParams()
92 params = this.restService.addRestGetParams(params, pagination, sort)
93
94 return this.authHttp
95 .get(VideoService.BASE_VIDEO_URL, { params })
96 .map(this.extractVideos)
97 .catch((res) => this.restExtractor.handleError(res))
98 }
99
100 searchVideos (search: Search, videoPagination: VideoPagination, sort: SortField): Observable<{ videos: Video[], totalVideos: number}> {
101 const url = VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value)
102
103 const pagination = this.videoPaginationToRestPagination(videoPagination)
104
105 let params = new HttpParams()
106 params = this.restService.addRestGetParams(params, pagination, sort)
107
108 if (search.field) params.set('field', search.field)
109
110 return this.authHttp
111 .get<ResultList<VideoServerModel>>(url, { params })
112 .map(this.extractVideos)
113 .catch((res) => this.restExtractor.handleError(res))
114 }
115
116 removeVideo (id: number) {
117 return this.authHttp
118 .delete(VideoService.BASE_VIDEO_URL + id)
119 .map(this.restExtractor.extractDataBool)
120 .catch((res) => this.restExtractor.handleError(res))
121 }
122
123 loadCompleteDescription (descriptionPath: string) {
124 return this.authHttp
125 .get(API_URL + descriptionPath)
126 .map(res => res['description'])
127 .catch((res) => this.restExtractor.handleError(res))
128 }
129
130 setVideoLike (id: number) {
131 return this.setVideoRate(id, 'like')
132 }
133
134 setVideoDislike (id: number) {
135 return this.setVideoRate(id, 'dislike')
136 }
137
138 getUserVideoRating (id: number): Observable<UserVideoRate> {
139 const url = UserService.BASE_USERS_URL + 'me/videos/' + id + '/rating'
140
141 return this.authHttp
142 .get(url)
143 .catch(res => this.restExtractor.handleError(res))
144 }
145
146 private videoPaginationToRestPagination (videoPagination: VideoPagination) {
147 const start: number = (videoPagination.currentPage - 1) * videoPagination.itemsPerPage
148 const count: number = videoPagination.itemsPerPage
149
150 return { start, count }
151 }
152
153 private setVideoRate (id: number, rateType: VideoRateType) {
154 const url = VideoService.BASE_VIDEO_URL + id + '/rate'
155 const body: UserVideoRateUpdate = {
156 rating: rateType
157 }
158
159 return this.authHttp
160 .put(url, body)
161 .map(this.restExtractor.extractDataBool)
162 .catch(res => this.restExtractor.handleError(res))
163 }
164
165 private extractVideos (result: ResultList<VideoServerModel>) {
166 const videosJson = result.data
167 const totalVideos = result.total
168 const videos = []
169
170 for (const videoJson of videosJson) {
171 videos.push(new Video(videoJson))
172 }
173
174 return { videos, totalVideos }
175 }
176}