Begin video watch design

pull/159/head
Chocobozzz 2017-12-06 17:15:59 +01:00
parent ce0e281d46
commit b1fa3eba70
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
29 changed files with 330 additions and 431 deletions

View File

@ -8,14 +8,9 @@
# Design
Inspirations from:
By [Olivier Massain](https://twitter.com/omassain)
* [Aurélien Salomon](https://dribbble.com/shots/1338727-Youtube-Redesign)
* [Wojciech Zieliński](https://dribbble.com/shots/3000315-youtube-concept)
Video.js theme:
* [zanechua](https://github.com/zanechua/videojs-sublime-inspired-skin)
Icons from [Robbie Pearce](https://robbiepearce.com/softies/)
# Fonts

View File

@ -0,0 +1,20 @@
import { Account as ServerAccount } from '../../../../../shared/models/accounts/account.model'
import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
export class Account implements ServerAccount {
id: number
uuid: string
name: string
host: string
followingCount: number
followersCount: number
createdAt: Date
updatedAt: Date
avatar: Avatar
static GET_ACCOUNT_AVATAR_PATH (account: Account) {
if (account && account.avatar) return account.avatar.path
return API_URL + '/client/assets/images/default-avatar.png'
}
}

View File

@ -20,6 +20,7 @@ import { RestExtractor, RestService } from './rest'
import { UserService } from './users'
import { VideoAbuseService } from './video-abuse'
import { VideoBlacklistService } from './video-blacklist'
import { VideoMiniatureComponent } from './video/video-miniature.component'
import { VideoThumbnailComponent } from './video/video-thumbnail.component'
import { VideoService } from './video/video.service'
@ -44,6 +45,7 @@ import { VideoService } from './video/video.service'
declarations: [
LoaderComponent,
VideoThumbnailComponent,
VideoMiniatureComponent,
NumberFormatterPipe,
FromNowPipe
],
@ -66,6 +68,7 @@ import { VideoService } from './video/video.service'
LoaderComponent,
VideoThumbnailComponent,
VideoMiniatureComponent,
NumberFormatterPipe,
FromNowPipe

View File

@ -1,5 +1,5 @@
import { hasUserRight, User as UserServerModel, UserRight, UserRole, VideoChannel } from '../../../../../shared'
import { Account } from '../../../../../shared/models/accounts'
import { Account } from '../account/account.model'
export type UserConstructorHash = {
id: number,
@ -52,8 +52,6 @@ export class User implements UserServerModel {
}
getAvatarPath () {
if (this.account && this.account.avatar) return this.account.avatar.path
return API_URL + '/client/assets/images/default-avatar.png'
return Account.GET_ACCOUNT_AVATAR_PATH(this.account)
}
}

View File

@ -12,7 +12,7 @@
>
<my-video-miniature
class="ng-animate"
*ngFor="let video of videos" [video]="video" [user]="user" [currentSort]="sort"
*ngFor="let video of videos" [video]="video" [user]="user"
>
</my-video-miniature>
</div>

View File

@ -1,3 +1,4 @@
import { Account } from '../../../../../shared/models/accounts'
import { Video } from '../../shared/video/video.model'
import { AuthUser } from '../../core'
import {
@ -10,7 +11,7 @@ import {
} from '../../../../../shared'
export class VideoDetails extends Video implements VideoDetailsServerModel {
account: string
accountName: string
by: string
createdAt: Date
updatedAt: Date
@ -44,6 +45,7 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
channel: VideoChannel
privacy: VideoPrivacy
privacyLabel: string
account: Account
constructor (hash: VideoDetailsServerModel) {
super(hash)
@ -53,6 +55,7 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
this.descriptionPath = hash.descriptionPath
this.files = hash.files
this.channel = hash.channel
this.account = hash.account
}
getAppropriateMagnetUri (actualDownloadSpeed = 0) {
@ -71,7 +74,7 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
}
isRemovableBy (user: AuthUser) {
return user && this.isLocal === true && (this.account === user.username || user.hasRight(UserRight.REMOVE_ANY_VIDEO))
return user && this.isLocal === true && (this.accountName === user.username || user.hasRight(UserRight.REMOVE_ANY_VIDEO))
}
isBlackistableBy (user: AuthUser) {
@ -79,6 +82,6 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
}
isUpdatableBy (user: AuthUser) {
return user && this.isLocal === true && user.username === this.account
return user && this.isLocal === true && user.username === this.accountName
}
}

View File

@ -1,7 +1,6 @@
import { Component, Input } from '@angular/core'
import { User } from '../../../shared'
import { SortField } from '../../../shared/video/sort-field.type'
import { Video } from '../../../shared/video/video.model'
import { User } from '../users'
import { Video } from './video.model'
@Component({
selector: 'my-video-miniature',
@ -9,7 +8,6 @@ import { Video } from '../../../shared/video/video.model'
templateUrl: './video-miniature.component.html'
})
export class VideoMiniatureComponent {
@Input() currentSort: SortField
@Input() user: User
@Input() video: Video

View File

@ -1,5 +1,5 @@
export interface VideoPagination {
currentPage: number
itemsPerPage: number
totalItems: number
totalItems?: number
}

View File

@ -1,8 +1,9 @@
import { Video as VideoServerModel } from '../../../../../shared'
import { User } from '../'
import { Account } from '../../../../../shared/models/accounts'
export class Video implements VideoServerModel {
account: string
accountName: string
by: string
createdAt: Date
updatedAt: Date
@ -31,6 +32,7 @@ export class Video implements VideoServerModel {
likes: number
dislikes: number
nsfw: boolean
account: Account
private static createByString (account: string, serverHost: string) {
return account + '@' + serverHost
@ -52,7 +54,7 @@ export class Video implements VideoServerModel {
absoluteAPIUrl = window.location.origin
}
this.account = hash.account
this.accountName = hash.accountName
this.createdAt = new Date(hash.createdAt.toString())
this.categoryLabel = hash.categoryLabel
this.category = hash.category
@ -80,7 +82,7 @@ export class Video implements VideoServerModel {
this.dislikes = hash.dislikes
this.nsfw = hash.nsfw
this.by = Video.createByString(hash.account, hash.serverHost)
this.by = Video.createByString(hash.accountName, hash.serverHost)
}
isVideoNSFWForUser (user: User) {

View File

@ -1,18 +1,3 @@
<div *ngIf="error" class="row">
<div class="alert alert-danger">
The video load seems to be abnormally long.
<ul>
<li>Maybe the server {{ video.serverHost }} is down :(</li>
<li>
If not, you can report an issue on
<a href="https://github.com/Chocobozzz/PeerTube/issues" title="Report an issue">
https://github.com/Chocobozzz/PeerTube/issues
</a>
</li>
</ul>
</div>
</div>
<div class="row">
<!-- We need the video container for videojs so we just hide it -->
<div [hidden]="videoNotFound" id="video-container">
@ -23,167 +8,153 @@
</div>
<!-- Video information -->
<div *ngIf="video !== null" id="video-info">
<div class="row video-name-views">
<div class="col-xs-8 col-md-8 video-name">
{{ video.name }}
</div>
<div *ngIf="video" class="margin-content video-bottom">
<div class="video-info">
<div class="video-info-name-actions">
<div class="video-info-name">{{ video.name }}</div>
<div class="col-xs-4 col-md-4 pull-right video-views">
{{ video.views}} views
</div>
</div>
<div class="video-info-actions">
<div class="action-button">
<span
class="icon icon-like" title="Like this video"
[ngClass]="{ 'interactive': isUserLoggedIn(), 'activated': userRating === 'like' }" (click)="setLike()"
></span>
</div>
<div class="row video-small-blocks">
<div class="col-xs-5 col-xs-3 col-md-3 video-small-block video-small-block-account">
<a class="option" title="Access to all videos of this user" [routerLink]="['/videos/list', { field: 'account', search: video.account }]">
<span class="glyphicon glyphicon-user"></span>
<span class="video-small-block-text">{{ video.by }}</span>
</a>
</div>
<div class="action-button">
<span
class="icon icon-dislike" title="Dislike this video"
[ngClass]="{ 'interactive': isUserLoggedIn(), 'activated': userRating === 'dislike' }" (click)="setDislike()"
></span>
</div>
<div class="col-xs-2 col-md-3 video-small-block video-small-block-share">
<a class="option" (click)="showShareModal()" title="Share the video">
<span class="glyphicon glyphicon-share"></span>
<span class="hidden-xs video-small-block-text">Share</span>
</a>
</div>
<div (click)="showShareModal()" class="action-button">
<span class="icon icon-share"></span>
Share
</div>
<div class="col-xs-2 col-md-3 video-small-block video-small-block-more">
<div class="video-small-block-dropdown" dropdown dropup="true" placement="right">
<a class="option" title="Access to more options" dropdownToggle>
<span class="glyphicon glyphicon-option-horizontal"></span>
<span class="hidden-xs video-small-block-text">More</span>
</a>
<div class="action-more" dropdown dropup="true" placement="right">
<div class="action-button" dropdownToggle>
<span class="icon icon-more"></span>
</div>
<ul *dropdownMenu class="dropdown-menu" id="more-menu" role="menu" aria-labelledby="single-button">
<li *ngIf="canUserUpdateVideo()" role="menuitem">
<a class="dropdown-item" title="Update this video" href="#" [routerLink]="[ '/videos/edit', video.uuid ]">
<span class="glyphicon glyphicon-pencil"></span> Update
</a>
</li>
<ul *dropdownMenu class="dropdown-menu" id="more-menu" role="menu" aria-labelledby="single-button">
<li *ngIf="canUserUpdateVideo()" role="menuitem">
<a class="dropdown-item" title="Update this video" href="#" [routerLink]="[ '/videos/edit', video.uuid ]">
<span class="glyphicon glyphicon-pencil"></span> Update
</a>
</li>
<li role="menuitem">
<a class="dropdown-item" title="Download the video" href="#" (click)="showDownloadModal($event)">
<span class="glyphicon glyphicon-download-alt"></span> Download
</a>
</li>
<li role="menuitem">
<a class="dropdown-item" title="Download the video" href="#" (click)="showDownloadModal($event)">
<span class="glyphicon glyphicon-download-alt"></span> Download
</a>
</li>
<li *ngIf="isUserLoggedIn()" role="menuitem">
<a class="dropdown-item" title="Report this video" href="#" (click)="showReportModal($event)">
<span class="glyphicon glyphicon-alert"></span> Report
</a>
</li>
<li *ngIf="isUserLoggedIn()" role="menuitem">
<a class="dropdown-item" title="Report this video" href="#" (click)="showReportModal($event)">
<span class="glyphicon glyphicon-alert"></span> Report
</a>
</li>
<li *ngIf="isVideoRemovable()" role="menuitem">
<a class="dropdown-item" title="Delete this video" href="#" (click)="removeVideo($event)">
<span class="glyphicon glyphicon-remove"></span> Delete
</a>
</li>
<li *ngIf="isVideoRemovable()" role="menuitem">
<a class="dropdown-item" title="Delete this video" href="#" (click)="removeVideo($event)">
<span class="glyphicon glyphicon-remove"></span> Delete
</a>
</li>
<li *ngIf="isVideoBlacklistable()" role="menuitem">
<a class="dropdown-item" title="Blacklist this video" href="#" (click)="blacklistVideo($event)">
<span class="glyphicon glyphicon-eye-close"></span> Blacklist
</a>
</li>
</ul>
<li *ngIf="isVideoBlacklistable()" role="menuitem">
<a class="dropdown-item" title="Blacklist this video" href="#" (click)="blacklistVideo($event)">
<span class="glyphicon glyphicon-eye-close"></span> Blacklist
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="col-xs-3 col-md-3 video-small-block video-small-block-rating">
<div class="video-small-block-like">
<span
class="glyphicon glyphicon-thumbs-up" title="Like this video"
[ngClass]="{ 'interactive': isUserLoggedIn(), 'activated': userRating === 'like' }" (click)="setLike()"
></span>
<span class="video-small-block-text">
{{ video.likes }}
</span>
</div>
<div class="video-small-block-dislike">
<span
class="glyphicon glyphicon-thumbs-down" title="Dislike this video"
[ngClass]="{ 'interactive': isUserLoggedIn(), 'activated': userRating === 'dislike' }" (click)="setDislike()"
></span>
<span class="video-small-block-text">
{{ video.dislikes }}
</span>
</div>
<div class="video-info-date-views">
{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views
</div>
</div>
<div class="row video-details">
<div class="video-details-date-description col-xs-8 col-md-9">
<div class="video-details-date">
Published on {{ video.createdAt | date:'short' }}
</div>
<div class="video-info-channel">
{{ video.channel.name }}
<!-- Here will be the subscribe button -->
</div>
<div class="video-details-description" [innerHTML]="videoHTMLDescription"></div>
<div class="video-info-by">
By {{ video.by }}
<img [src]="getAvatarPath()" alt="Account avatar" />
</div>
<div class="video-details-description-more" *ngIf="completeDescriptionShown === false && video.description.length === 250" (click)="showMoreDescription()">
<div class="video-info-description">
<div class="video-info-description-html" [innerHTML]="videoHTMLDescription"></div>
<div class="video-info-description-more" *ngIf="completeDescriptionShown === false && video.description.length === 250" (click)="showMoreDescription()">
Show more
<span *ngIf="descriptionLoading === false" class="glyphicon glyphicon-menu-down"></span>
<my-loader class="description-loading" [loading]="descriptionLoading"></my-loader>
</div>
<div *ngIf="completeDescriptionShown === true" (click)="showLessDescription()" class="video-details-description-more">
<div *ngIf="completeDescriptionShown === true" (click)="showLessDescription()" class="video-info-description-more">
Show less
<span *ngIf="descriptionLoading === false" class="glyphicon glyphicon-menu-up"></span>
</div>
</div>
<div class="video-details-attributes col-xs-4 col-md-3">
<div class="video-details-attribute">
<span class="video-details-attribute-label">
Privacy:
<div class="video-attributes">
<div class="video-attribute">
<span class="video-attribute-label">
Privacy
</span>
<span class="video-details-attribute-value">
<span class="video-attribute-value">
{{ video.privacyLabel }}
</span>
</div>
<div class="video-details-attribute">
<span class="video-details-attribute-label">
Category:
<div class="video-attribute">
<span class="video-attribute-label">
Category
</span>
<span class="video-details-attribute-value">
<span class="video-attribute-value">
{{ video.categoryLabel }}
</span>
</div>
<div class="video-details-attribute">
<span class="video-details-attribute-label">
Licence:
<div class="video-attribute">
<span class="video-attribute-label">
Licence
</span>
<span class="video-details-attribute-value">
<span class="video-attribute-value">
{{ video.licenceLabel }}
</span>
</div>
<div class="video-details-attribute">
<span class="video-details-attribute-label">
Language:
<div class="video-attribute">
<span class="video-attribute-label">
Language
</span>
<span class="video-details-attribute-value">
<span class="video-attribute-value">
{{ video.languageLabel }}
</span>
</div>
<div class="video-details-attribute">
<span class="video-details-attribute-label">
Tags:
<div class="video-attribute">
<span class="video-attribute-label">
Tags
</span>
<div class="video-details-tags">
<a *ngFor="let tag of video.tags" [routerLink]="['/videos/list', { field: 'tags', search: tag }]" class="label label-primary">
{{ tag }}
</a>
</div>
<span class="video-attribute-value">
{{ getVideoTags() }}
</span>
</div>
</div>
</div>
<div class="other-videos">
<div *ngFor="let video of otherVideos">
<my-video-miniature [video]="video" [user]="user"></my-video-miniature>
</div>
</div>
</div>

View File

@ -17,167 +17,108 @@
font-weight: bold;
}
#torrent-info {
font-size: 10px;
margin-top: 10px;
text-align: center;
.video-bottom {
margin-top: 40px;
display: flex;
div {
min-width: 60px;
}
}
.video-info {
flex-grow: 1;
margin-right: 28px;
#video-info {
.video-name-views {
font-weight: bold;
font-size: 18px;
min-height: $video-watch-title-height;
display: flex;
align-items: center;
.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;
.video-info-name-actions {
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
align-items: 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;
}
.video-info-name {
font-size: 27px;
font-weight: $font-semibold;
flex-grow: 1;
}
.option .glyphicon {
font-size: 22px;
color: inherit;
opacity: 0.15;
margin-bottom: 10px;
transition: opacity 0.3s;
}
.video-info-actions {
.action-button {
@include peertube-button;
.video-small-block-text {
font-size: 15px;
font-weight: bold;
}
}
font-size: 15px;
font-weight: $font-semibold;
color: #585858;
background-color: #E5E5E5;
display: inline-block;
padding: 0 10px 0 10px;
.video-small-block:not(:last-child) {
border-width: 0 1px 0 0;
border-color: $video-watch-border-color;
border-style: solid;
}
&:hover {
background-color: #EFEFEF;
}
}
.video-small-block-account, .video-small-block-more {
a.option {
display: block;
.action-more {
display: inline-block;
}
.glyphicon {
display: block;
.icon {
display: inline-block;
background-repeat: no-repeat;
background-size: contain;
width: 21px;
height: 21px;
vertical-align: middle;
position: relative;
top: -2px;
&.icon-like {
background-image: url('../../../assets/images/video/like.svg');
}
&.icon-dislike {
background-image: url('../../../assets/images/video/dislike.svg');
}
&.icon-share {
background-image: url('../../../assets/images/video/share.svg');
}
&.icon-more {
background-image: url('../../../assets/images/video/more.svg');
}
}
}
}
.video-small-block-share, .video-small-block-more {
a.option {
display: block;
.video-info-date-views {
font-size: 16px;
margin-bottom: 10px;
}
.glyphicon {
display: block;
}
.video-info-channel {
font-weight: $font-semibold;
font-size: 15px;
}
.video-info-by {
display: flex;
align-items: center;
font-size: 13px;
img {
width: 16px;
height: 16px;
margin-left: 3px;
}
}
.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-info-description {
margin: 20px 0;
font-size: 15px;
.description-loading {
display: inline-block;
}
.video-details-date {
font-weight: bold;
margin-bottom: 30px;
}
.video-details-description-more {
.video-info-description-more {
cursor: pointer;
margin-top: 15px;
font-weight: bold;
color: #acaeb7;
font-weight: $font-semibold;
color: #585858;
font-size: 14px;
.glyphicon {
position: relative;
@ -186,109 +127,20 @@
}
}
.video-details-attributes {
font-weight: bold;
font-size: 12px;
.video-attributes {
.video-attribute {
font-size: 13px;
display: block;
margin-bottom: 12px;
.video-details-attribute {
display: flex;
.video-details-attribute-label {
color: $video-watch-info-color;
flex-basis: 60px;
flex-grow: 0;
flex-shrink: 0;
margin-right: 5px;
.video-attribute-label {
width: 86px;
display: inline-block;
color: #585858;
font-weight: $font-bold;
}
}
}
.video-details-tags {
display: flex;
flex-wrap: wrap;
a {
margin: 0 3px 3px 0;
font-size: 11px;
}
}
}
@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-account {
padding-left: 10px;
padding-right: 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;
}
}
}
}
@media screen and (max-width: 500px) {
.video-name-views {
font-size: 16px !important;
}
// Keep the same hierarchy than max-width: 800px
.video-small-blocks {
a, .video-small-block-text {
font-size: 10px !important;
}
.video-small-block-account {
padding-left: 5px;
padding-right: 5px;
}
}
.video-details {
.video-details-date-description {
margin-bottom: 30px;
width: 100%;
.video-details-date {
margin-bottom: 15px;
}
}
.video-details-attributes {
padding-left: 10px;
padding-right: 10px;
}
}
}
}

View File

@ -10,6 +10,8 @@ import { UserVideoRateType, VideoRateType } from '../../../../../shared'
import '../../../assets/player/peertube-videojs-plugin'
import { AuthService, ConfirmService } from '../../core'
import { VideoBlacklistService } from '../../shared'
import { Account } from '../../shared/account/account.model'
import { Video } from '../../shared/video/video.model'
import { MarkdownService } from '../shared'
import { VideoDownloadComponent } from './video-download.component'
import { VideoReportComponent } from './video-report.component'
@ -26,6 +28,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
@ViewChild('videoShareModal') videoShareModal: VideoShareComponent
@ViewChild('videoReportModal') videoReportModal: VideoReportComponent
otherVideos: Video[] = []
error = false
loading = false
player: videojs.Player
@ -57,6 +61,13 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
) {}
ngOnInit () {
this.videoService.getVideos({ currentPage: 1, itemsPerPage: 5 }, '-createdAt')
.subscribe(
data => this.otherVideos = data.videos,
err => console.error(err)
)
this.paramsSub = this.route.params.subscribe(routeParams => {
let uuid = routeParams['uuid']
this.videoService.getVideo(uuid).subscribe(
@ -114,27 +125,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
)
}
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()
@ -165,7 +155,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
}
showLessDescription () {
this.updateVideoDescription(this.shortVideoDescription)
this.completeDescriptionShown = false
}
@ -222,6 +211,16 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
return this.video.isBlackistableBy(this.authService.getUser())
}
getAvatarPath () {
return Account.GET_ACCOUNT_AVATAR_PATH(this.video.account)
}
getVideoTags () {
if (!this.video || Array.isArray(this.video.tags) === false) return []
return this.video.tags.join(', ')
}
private updateVideoDescription (description: string) {
this.video.description = description
this.setVideoDescriptionHTML()

View File

@ -1,4 +1,3 @@
export * from './video-recently-added.component'
export * from './video-trending.component'
export * from './video-search.component'
export * from './shared'

View File

@ -1 +0,0 @@
export * from './video-miniature.component'

View File

@ -1,6 +1,6 @@
import { NgModule } from '@angular/core'
import { SharedModule } from '../shared'
import { VideoMiniatureComponent, VideoSearchComponent } from './video-list'
import { VideoSearchComponent } from './video-list'
import { VideoRecentlyAddedComponent } from './video-list/video-recently-added.component'
import { VideoTrendingComponent } from './video-list/video-trending.component'
import { VideosRoutingModule } from './videos-routing.module'
@ -17,7 +17,6 @@ import { VideosComponent } from './videos.component'
VideoTrendingComponent,
VideoRecentlyAddedComponent,
VideoMiniatureComponent,
VideoSearchComponent
],

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g id="Artboard-4" transform="translate(-752.000000, -1090.000000)" stroke="#585858" stroke-width="2">
<g id="Extras" transform="translate(48.000000, 1046.000000)">
<g id="thumbs-down" transform="translate(704.000000, 44.000000)">
<path d="M6,16 C6,18.5 6.5,21 8,21 L16.9938335,21 C17.5495239,21 18.1819788,20.5956028 18.4072817,20.0949295 L20.8562951,14.6526776 C21.7640882,12.6353595 20.7154925,11 18.5092545,11 L15.5,11 C15.5,11 18.5,5 15,5 C12.5,5 11.5,11 8,11 C6.5,11 6,13.5 6,16 Z" id="Path-188" stroke-linejoin="round" transform="translate(13.591488, 13.000000) scale(1, -1) translate(-13.591488, -13.000000) "></path>
<path d="M4,4.5 C4,4.5 3,7 3,10 C3,13 4,15.5 4,15.5" id="Path-189" transform="translate(3.500000, 10.000000) scale(1, -1) translate(-3.500000, -10.000000) "></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
<title>thumbs-up</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g id="Artboard-4" transform="translate(-708.000000, -643.000000)" stroke="#585858" stroke-width="2">
<g id="256" transform="translate(708.000000, 643.000000)">
<path d="M6,14 C6,16.5 6.5,19 8,19 L16.9938335,19 C17.5495239,19 18.1819788,18.5956028 18.4072817,18.0949295 L20.8562951,12.6526776 C21.7640882,10.6353595 20.7154925,9 18.5092545,9 L15.5,9 C15.5,9 18.5,3 15,3 C12.5,3 11.5,9 8,9 C6.5,9 6,11.5 6,14 Z" id="Path-188" stroke-linejoin="round"></path>
<path d="M4,8.5 C4,8.5 3,11 3,14 C3,17 4,19.5 4,19.5" id="Path-189"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Artboard-4" transform="translate(-444.000000, -115.000000)" fill="#585858">
<g id="10" transform="translate(444.000000, 115.000000)">
<path d="M10,12 C10,10.8954305 10.8877296,10 12,10 C13.1045695,10 14,10.8877296 14,12 C14,13.1045695 13.1122704,14 12,14 C10.8954305,14 10,13.1122704 10,12 Z M17,12 C17,10.8954305 17.8877296,10 19,10 C20.1045695,10 21,10.8877296 21,12 C21,13.1045695 20.1122704,14 19,14 C17.8954305,14 17,13.1122704 17,12 Z M3,12 C3,10.8954305 3.88772964,10 5,10 C6.1045695,10 7,10.8877296 7,12 C7,13.1045695 6.11227036,14 5,14 C3.8954305,14 3,13.1122704 3,12 Z" id="Combined-Shape"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 982 B

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
<title>share</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g id="Artboard-4" transform="translate(-312.000000, -203.000000)" stroke="#585858" stroke-width="2">
<g id="47" transform="translate(312.000000, 203.000000)">
<path d="M20,15 L20,18.0026083 C20,19.1057373 19.1073772,20 18.0049107,20 L5.99508929,20 C4.8932319,20 4,19.1073772 4,18.0049107 L4,5.99508929 C4,4.8932319 4.89585781,4 5.9973917,4 L9,4" id="Rectangle-460"></path>
<polyline id="Path-93" stroke-linejoin="round" points="13 4 20.0207973 4 20.0207973 11.0191059"></polyline>
<path d="M19,5 L12,12" id="Path-94" stroke-linejoin="round"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -486,7 +486,7 @@ toFormattedJSON = function (this: VideoInstance) {
description: this.getTruncatedDescription(),
serverHost,
isLocal: this.isOwned(),
account: this.VideoChannel.Account.name,
accountName: this.VideoChannel.Account.name,
duration: this.duration,
views: this.views,
likes: this.likes,
@ -514,6 +514,7 @@ toFormattedDetailsJSON = function (this: VideoInstance) {
privacy: this.privacy,
descriptionPath: this.getDescriptionPath(),
channel: this.VideoChannel.toFormattedJSON(),
account: this.VideoChannel.Account.toFormattedJSON(),
files: []
}

View File

@ -227,7 +227,7 @@ describe('Test follows', function () {
expect(videoDetails.nsfw).to.be.ok
expect(videoDetails.description).to.equal('my super description')
expect(videoDetails.serverHost).to.equal('localhost:9003')
expect(videoDetails.account).to.equal('root')
expect(videoDetails.accountName).to.equal('root')
expect(videoDetails.likes).to.equal(1)
expect(videoDetails.dislikes).to.equal(1)
expect(videoDetails.isLocal).to.be.false

View File

@ -111,13 +111,14 @@ describe('Test multiple servers', function () {
expect(video.tags).to.deep.equal([ 'tag1p1', 'tag2p1' ])
expect(dateIsValid(video.createdAt)).to.be.true
expect(dateIsValid(video.updatedAt)).to.be.true
expect(video.account).to.equal('root')
expect(video.accountName).to.equal('root')
const res2 = await getVideo(server.url, video.uuid)
const videoDetails = res2.body
expect(videoDetails.channel.name).to.equal('my channel')
expect(videoDetails.channel.description).to.equal('super channel')
expect(videoDetails.account.name).to.equal('root')
expect(dateIsValid(videoDetails.channel.createdAt)).to.be.true
expect(dateIsValid(videoDetails.channel.updatedAt)).to.be.true
expect(videoDetails.files).to.have.lengthOf(1)
@ -201,7 +202,7 @@ describe('Test multiple servers', function () {
expect(video.tags).to.deep.equal([ 'tag1p2', 'tag2p2', 'tag3p2' ])
expect(dateIsValid(video.createdAt)).to.be.true
expect(dateIsValid(video.updatedAt)).to.be.true
expect(video.account).to.equal('user1')
expect(video.accountName).to.equal('user1')
if (server.url !== 'http://localhost:9002') {
expect(video.isLocal).to.be.false
@ -316,7 +317,7 @@ describe('Test multiple servers', function () {
expect(video1.serverHost).to.equal('localhost:9003')
expect(video1.duration).to.equal(5)
expect(video1.tags).to.deep.equal([ 'tag1p3' ])
expect(video1.account).to.equal('root')
expect(video1.accountName).to.equal('root')
expect(dateIsValid(video1.createdAt)).to.be.true
expect(dateIsValid(video1.updatedAt)).to.be.true
@ -342,7 +343,7 @@ describe('Test multiple servers', function () {
expect(video2.serverHost).to.equal('localhost:9003')
expect(video2.duration).to.equal(5)
expect(video2.tags).to.deep.equal([ 'tag2p3', 'tag3p3', 'tag4p3' ])
expect(video2.account).to.equal('root')
expect(video2.accountName).to.equal('root')
expect(dateIsValid(video2.createdAt)).to.be.true
expect(dateIsValid(video2.updatedAt)).to.be.true
@ -690,7 +691,7 @@ describe('Test multiple servers', function () {
expect(baseVideo.licence).to.equal(video.licence)
expect(baseVideo.category).to.equal(video.category)
expect(baseVideo.nsfw).to.equal(video.nsfw)
expect(baseVideo.account).to.equal(video.account)
expect(baseVideo.accountName).to.equal(video.accountName)
expect(baseVideo.tags).to.deep.equal(video.tags)
}
})

View File

@ -46,7 +46,7 @@ describe('Test services', function () {
expect(res.body.html).to.equal(expectedHtml)
expect(res.body.title).to.equal(server.video.name)
expect(res.body.author_name).to.equal(server.video.account)
expect(res.body.author_name).to.equal(server.video.accountName)
expect(res.body.width).to.equal(560)
expect(res.body.height).to.equal(315)
expect(res.body.thumbnail_url).to.equal(expectedThumbnailUrl)
@ -66,7 +66,7 @@ describe('Test services', function () {
expect(res.body.html).to.equal(expectedHtml)
expect(res.body.title).to.equal(server.video.name)
expect(res.body.author_name).to.equal(server.video.account)
expect(res.body.author_name).to.equal(server.video.accountName)
expect(res.body.height).to.equal(50)
expect(res.body.width).to.equal(50)
expect(res.body).to.not.have.property('thumbnail_url')

View File

@ -127,7 +127,7 @@ describe('Test a single server', function () {
expect(video.nsfw).to.be.ok
expect(video.description).to.equal('my super description')
expect(video.serverHost).to.equal('localhost:9001')
expect(video.account).to.equal('root')
expect(video.accountName).to.equal('root')
expect(video.isLocal).to.be.true
expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
expect(dateIsValid(video.createdAt)).to.be.true
@ -176,7 +176,7 @@ describe('Test a single server', function () {
expect(video.nsfw).to.be.ok
expect(video.description).to.equal('my super description')
expect(video.serverHost).to.equal('localhost:9001')
expect(video.account).to.equal('root')
expect(video.accountName).to.equal('root')
expect(video.isLocal).to.be.true
expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
expect(dateIsValid(video.createdAt)).to.be.true
@ -243,7 +243,7 @@ describe('Test a single server', function () {
expect(video.nsfw).to.be.ok
expect(video.description).to.equal('my super description')
expect(video.serverHost).to.equal('localhost:9001')
expect(video.account).to.equal('root')
expect(video.accountName).to.equal('root')
expect(video.isLocal).to.be.true
expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
expect(dateIsValid(video.createdAt)).to.be.true
@ -298,7 +298,7 @@ describe('Test a single server', function () {
// expect(video.nsfw).to.be.ok
// expect(video.description).to.equal('my super description')
// expect(video.serverHost).to.equal('localhost:9001')
// expect(video.account).to.equal('root')
// expect(video.accountName).to.equal('root')
// expect(video.isLocal).to.be.true
// expect(video.tags).to.deep.equal([ 'tag1', 'tag2', 'tag3' ])
// expect(dateIsValid(video.createdAt)).to.be.true
@ -563,7 +563,8 @@ describe('Test a single server', function () {
expect(video.nsfw).to.be.ok
expect(video.description).to.equal('my super description updated')
expect(video.serverHost).to.equal('localhost:9001')
expect(video.account).to.equal('root')
expect(video.accountName).to.equal('root')
expect(video.account.name).to.equal('root')
expect(video.isLocal).to.be.true
expect(video.tags).to.deep.equal([ 'tagup1', 'tagup2' ])
expect(dateIsValid(video.createdAt)).to.be.true
@ -612,7 +613,7 @@ describe('Test a single server', function () {
expect(video.nsfw).to.be.ok
expect(video.description).to.equal('my super description updated')
expect(video.serverHost).to.equal('localhost:9001')
expect(video.account).to.equal('root')
expect(video.accountName).to.equal('root')
expect(video.isLocal).to.be.true
expect(video.tags).to.deep.equal([ 'supertag', 'tag1', 'tag2' ])
expect(dateIsValid(video.createdAt)).to.be.true
@ -652,7 +653,7 @@ describe('Test a single server', function () {
expect(video.nsfw).to.be.ok
expect(video.description).to.equal('hello everybody')
expect(video.serverHost).to.equal('localhost:9001')
expect(video.account).to.equal('root')
expect(video.accountName).to.equal('root')
expect(video.isLocal).to.be.true
expect(video.tags).to.deep.equal([ 'supertag', 'tag1', 'tag2' ])
expect(dateIsValid(video.createdAt)).to.be.true

View File

@ -117,7 +117,7 @@ describe('Test users', function () {
const res = await getVideosList(server.url)
const video = res.body.data[ 0 ]
expect(video.account)
expect(video.accountName)
.to
.equal('root')
videoId = video.id
@ -487,7 +487,7 @@ describe('Test users', function () {
.equal(1)
const video = res.body.data[ 0 ]
expect(video.account)
expect(video.accountName)
.to
.equal('root')
})

View File

@ -24,7 +24,7 @@ interface ServerInfo {
id: number
uuid: string
name: string
account: string
accountName: string
}
remoteVideo?: {

View File

@ -1,3 +1,4 @@
import { Account } from '../accounts'
import { VideoChannel } from './video-channel.model'
import { VideoPrivacy } from './video-privacy.enum'
@ -13,7 +14,7 @@ export interface VideoFile {
export interface Video {
id: number
uuid: string
account: string
accountName: string
createdAt: Date | string
updatedAt: Date | string
categoryLabel: string
@ -43,4 +44,5 @@ export interface VideoDetails extends Video {
descriptionPath: string
channel: VideoChannel
files: VideoFile[]
account: Account
}