Client: Add ability to update video channel avatar
This commit is contained in:
parent
4bbfc6c606
commit
52d9f792b3
|
@ -1,20 +1,4 @@
|
||||||
<div class="user">
|
<my-actor-avatar-info [actor]="user.account" (avatarChange)="onAvatarChange($event)"></my-actor-avatar-info>
|
||||||
<img [src]="user.accountAvatarUrl" alt="Avatar" />
|
|
||||||
|
|
||||||
<div class="user-info">
|
|
||||||
<div class="user-info-names">
|
|
||||||
<div class="user-info-display-name">{{ user.account?.displayName }}</div>
|
|
||||||
<div class="user-info-username">{{ user.username }}</div>
|
|
||||||
</div>
|
|
||||||
<div i18n class="user-info-followers">{{ user.account?.followersCount }} subscribers</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="button-file">
|
|
||||||
<span i18n>Change your avatar</span>
|
|
||||||
<input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="changeAvatar()" />
|
|
||||||
</div>
|
|
||||||
<div i18n class="file-max-size">(extensions: {{ avatarExtensions }}, max size: {{ maxAvatarSize | bytes }})</div>
|
|
||||||
|
|
||||||
<div class="user-quota">
|
<div class="user-quota">
|
||||||
<span i18n class="user-quota-label">Video quota:</span> {{ userVideoQuotaUsed | bytes: 0 }} / {{ userVideoQuota }}
|
<span i18n class="user-quota-label">Video quota:</span> {{ userVideoQuotaUsed | bytes: 0 }} / {{ userVideoQuota }}
|
||||||
|
|
|
@ -1,55 +1,6 @@
|
||||||
@import '_variables';
|
@import '_variables';
|
||||||
@import '_mixins';
|
@import '_mixins';
|
||||||
|
|
||||||
.user {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
img {
|
|
||||||
@include avatar(50px);
|
|
||||||
|
|
||||||
margin-right: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info {
|
|
||||||
.user-info-names {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.user-info-display-name {
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: $font-bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info-username {
|
|
||||||
margin-left: 7px;
|
|
||||||
position: relative;
|
|
||||||
top: 2px;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #777272;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info-followers {
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-file {
|
|
||||||
@include peertube-button-file(160px);
|
|
||||||
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-max-size {
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
top: -10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-quota {
|
.user-quota {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
|
|
@ -13,8 +13,6 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
styleUrls: [ './my-account-settings.component.scss' ]
|
styleUrls: [ './my-account-settings.component.scss' ]
|
||||||
})
|
})
|
||||||
export class MyAccountSettingsComponent implements OnInit {
|
export class MyAccountSettingsComponent implements OnInit {
|
||||||
@ViewChild('avatarfileInput') avatarfileInput
|
|
||||||
|
|
||||||
user: User = null
|
user: User = null
|
||||||
userVideoQuota = '0'
|
userVideoQuota = '0'
|
||||||
userVideoQuotaUsed = 0
|
userVideoQuotaUsed = 0
|
||||||
|
@ -48,16 +46,7 @@ export class MyAccountSettingsComponent implements OnInit {
|
||||||
.subscribe(data => this.userVideoQuotaUsed = data.videoQuotaUsed)
|
.subscribe(data => this.userVideoQuotaUsed = data.videoQuotaUsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
changeAvatar () {
|
onAvatarChange (formData: FormData) {
|
||||||
const avatarfile = this.avatarfileInput.nativeElement.files[ 0 ]
|
|
||||||
if (avatarfile.size > this.maxAvatarSize) {
|
|
||||||
this.notificationsService.error('Error', 'This image is too large.')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const formData = new FormData()
|
|
||||||
formData.append('avatarfile', avatarfile)
|
|
||||||
|
|
||||||
this.userService.changeAvatar(formData)
|
this.userService.changeAvatar(formData)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
data => {
|
data => {
|
||||||
|
@ -69,12 +58,4 @@ export class MyAccountSettingsComponent implements OnInit {
|
||||||
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get maxAvatarSize () {
|
|
||||||
return this.serverService.getConfig().avatar.file.size.max
|
|
||||||
}
|
|
||||||
|
|
||||||
get avatarExtensions () {
|
|
||||||
return this.serverService.getConfig().avatar.file.extensions.join(',')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
<my-actor-avatar-info
|
||||||
|
*ngIf="isCreation() === false && videoChannelToUpdate"
|
||||||
|
[actor]="videoChannelToUpdate" (avatarChange)="onAvatarChange($event)"
|
||||||
|
></my-actor-avatar-info>
|
||||||
|
|
||||||
<div i18n class="form-sub-title" *ngIf="isCreation() === true">Create a video channel</div>
|
<div i18n class="form-sub-title" *ngIf="isCreation() === true">Create a video channel</div>
|
||||||
<div i18n class="form-sub-title" *ngIf="isCreation() === false">Update {{ videoChannel?.displayName }}</div>
|
|
||||||
|
|
||||||
<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
|
<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,11 @@
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my-actor-avatar-info {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
input[type=text] {
|
input[type=text] {
|
||||||
@include peertube-input-text(340px);
|
@include peertube-input-text(340px);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, OnDestroy, OnInit } from '@angular/core'
|
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
|
||||||
import { ActivatedRoute, Router } from '@angular/router'
|
import { ActivatedRoute, Router } from '@angular/router'
|
||||||
import { NotificationsService } from 'angular2-notifications'
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit'
|
import { MyAccountVideoChannelEdit } from './my-account-video-channel-edit'
|
||||||
|
@ -6,7 +6,7 @@ import { VideoChannelUpdate } from '../../../../../shared/models/videos'
|
||||||
import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
|
import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
|
||||||
import { Subscription } from 'rxjs'
|
import { Subscription } from 'rxjs'
|
||||||
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
|
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
|
||||||
import { AuthService } from '@app/core'
|
import { AuthService, ServerService } from '@app/core'
|
||||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
|
||||||
import { VideoChannelValidatorsService } from '@app/shared/forms/form-validators/video-channel-validators.service'
|
import { VideoChannelValidatorsService } from '@app/shared/forms/form-validators/video-channel-validators.service'
|
||||||
|
@ -17,6 +17,8 @@ import { VideoChannelValidatorsService } from '@app/shared/forms/form-validators
|
||||||
styleUrls: [ './my-account-video-channel-edit.component.scss' ]
|
styleUrls: [ './my-account-video-channel-edit.component.scss' ]
|
||||||
})
|
})
|
||||||
export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelEdit implements OnInit, OnDestroy {
|
export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelEdit implements OnInit, OnDestroy {
|
||||||
|
@ViewChild('avatarfileInput') avatarfileInput
|
||||||
|
|
||||||
error: string
|
error: string
|
||||||
|
|
||||||
private videoChannelToUpdate: VideoChannel
|
private videoChannelToUpdate: VideoChannel
|
||||||
|
@ -30,7 +32,8 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private videoChannelService: VideoChannelService,
|
private videoChannelService: VideoChannelService,
|
||||||
private i18n: I18n
|
private i18n: I18n,
|
||||||
|
private serverService: ServerService
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
|
@ -89,6 +92,27 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAvatarChange (formData: FormData) {
|
||||||
|
this.videoChannelService.changeVideoChannelAvatar(this.videoChannelToUpdate.uuid, formData)
|
||||||
|
.subscribe(
|
||||||
|
data => {
|
||||||
|
this.notificationsService.success(this.i18n('Success'), this.i18n('Avatar changed.'))
|
||||||
|
|
||||||
|
this.videoChannelToUpdate.updateAvatar(data.avatar)
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
get maxAvatarSize () {
|
||||||
|
return this.serverService.getConfig().avatar.file.size.max
|
||||||
|
}
|
||||||
|
|
||||||
|
get avatarExtensions () {
|
||||||
|
return this.serverService.getConfig().avatar.file.extensions.join(',')
|
||||||
|
}
|
||||||
|
|
||||||
isCreation () {
|
isCreation () {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { MyAccountProfileComponent } from '@app/+my-account/my-account-settings/
|
||||||
import { MyAccountVideoChannelsComponent } from '@app/+my-account/my-account-video-channels/my-account-video-channels.component'
|
import { MyAccountVideoChannelsComponent } from '@app/+my-account/my-account-video-channels/my-account-video-channels.component'
|
||||||
import { MyAccountVideoChannelCreateComponent } from '@app/+my-account/my-account-video-channels/my-account-video-channel-create.component'
|
import { MyAccountVideoChannelCreateComponent } from '@app/+my-account/my-account-video-channels/my-account-video-channel-create.component'
|
||||||
import { MyAccountVideoChannelUpdateComponent } from '@app/+my-account/my-account-video-channels/my-account-video-channel-update.component'
|
import { MyAccountVideoChannelUpdateComponent } from '@app/+my-account/my-account-video-channels/my-account-video-channel-update.component'
|
||||||
|
import { ActorAvatarInfoComponent } from '@app/+my-account/shared/actor-avatar-info.component'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -26,7 +27,8 @@ import { MyAccountVideoChannelUpdateComponent } from '@app/+my-account/my-accoun
|
||||||
MyAccountVideosComponent,
|
MyAccountVideosComponent,
|
||||||
MyAccountVideoChannelsComponent,
|
MyAccountVideoChannelsComponent,
|
||||||
MyAccountVideoChannelCreateComponent,
|
MyAccountVideoChannelCreateComponent,
|
||||||
MyAccountVideoChannelUpdateComponent
|
MyAccountVideoChannelUpdateComponent,
|
||||||
|
ActorAvatarInfoComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
exports: [
|
exports: [
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<ng-container *ngIf="actor">
|
||||||
|
<div class="actor">
|
||||||
|
<img [src]="actor.avatarUrl" alt="Avatar" />
|
||||||
|
|
||||||
|
<div class="actor-info">
|
||||||
|
<div class="actor-info-names">
|
||||||
|
<div class="actor-info-display-name">{{ actor.displayName }}</div>
|
||||||
|
<div class="actor-info-username">{{ actor.name }}</div>
|
||||||
|
</div>
|
||||||
|
<div i18n class="actor-info-followers">{{ actor.followersCount }} subscribers</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-file">
|
||||||
|
<span i18n>Change the avatar</span>
|
||||||
|
<input #avatarfileInput type="file" name="avatarfile" id="avatarfile" [accept]="avatarExtensions" (change)="onAvatarChange()" />
|
||||||
|
</div>
|
||||||
|
<div i18n class="file-max-size">(extensions: {{ avatarExtensions }}, max size: {{ maxAvatarSize | bytes }})</div>
|
||||||
|
</ng-container>
|
|
@ -0,0 +1,51 @@
|
||||||
|
@import '_variables';
|
||||||
|
@import '_mixins';
|
||||||
|
|
||||||
|
.actor {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
img {
|
||||||
|
@include avatar(50px);
|
||||||
|
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actor-info {
|
||||||
|
.actor-info-names {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.actor-info-display-name {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: $font-bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actor-info-username {
|
||||||
|
margin-left: 7px;
|
||||||
|
position: relative;
|
||||||
|
top: 2px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #777272;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.actor-info-followers {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-file {
|
||||||
|
@include peertube-button-file(160px);
|
||||||
|
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.file-max-size {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
top: -10px;
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'
|
||||||
|
import { AuthService } from '../../core'
|
||||||
|
import { ServerService } from '../../core/server'
|
||||||
|
import { UserService } from '../../shared/users'
|
||||||
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
|
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
|
||||||
|
import { Account } from '@app/shared/account/account.model'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-actor-avatar-info',
|
||||||
|
templateUrl: './actor-avatar-info.component.html',
|
||||||
|
styleUrls: [ './actor-avatar-info.component.scss' ]
|
||||||
|
})
|
||||||
|
export class ActorAvatarInfoComponent {
|
||||||
|
@ViewChild('avatarfileInput') avatarfileInput
|
||||||
|
|
||||||
|
@Input() actor: VideoChannel | Account
|
||||||
|
|
||||||
|
@Output() avatarChange = new EventEmitter<FormData>()
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private userService: UserService,
|
||||||
|
private authService: AuthService,
|
||||||
|
private serverService: ServerService,
|
||||||
|
private notificationsService: NotificationsService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
onAvatarChange () {
|
||||||
|
const avatarfile = this.avatarfileInput.nativeElement.files[ 0 ]
|
||||||
|
if (avatarfile.size > this.maxAvatarSize) {
|
||||||
|
this.notificationsService.error('Error', 'This image is too large.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('avatarfile', avatarfile)
|
||||||
|
|
||||||
|
this.avatarChange.emit(formData)
|
||||||
|
}
|
||||||
|
|
||||||
|
get maxAvatarSize () {
|
||||||
|
return this.serverService.getConfig().avatar.file.size.max
|
||||||
|
}
|
||||||
|
|
||||||
|
get avatarExtensions () {
|
||||||
|
return this.serverService.getConfig().avatar.file.extensions.join(',')
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,6 +45,16 @@ export abstract class Actor implements ActorServer {
|
||||||
this.updatedAt = new Date(hash.updatedAt.toString())
|
this.updatedAt = new Date(hash.updatedAt.toString())
|
||||||
this.avatar = hash.avatar
|
this.avatar = hash.avatar
|
||||||
|
|
||||||
|
this.updateComputedAttributes()
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAvatar (newAvatar: Avatar) {
|
||||||
|
this.avatar = newAvatar
|
||||||
|
|
||||||
|
this.updateComputedAttributes()
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateComputedAttributes () {
|
||||||
this.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(this)
|
this.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ export class User implements UserServerModel {
|
||||||
account: Account
|
account: Account
|
||||||
videoChannels: VideoChannel[]
|
videoChannels: VideoChannel[]
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
accountAvatarUrl: string
|
|
||||||
|
|
||||||
constructor (hash: UserConstructorHash) {
|
constructor (hash: UserConstructorHash) {
|
||||||
this.id = hash.id
|
this.id = hash.id
|
||||||
|
@ -65,8 +64,12 @@ export class User implements UserServerModel {
|
||||||
if (hash.createdAt !== undefined) {
|
if (hash.createdAt !== undefined) {
|
||||||
this.createdAt = hash.createdAt
|
this.createdAt = hash.createdAt
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.updateComputedAttributes()
|
get accountAvatarUrl () {
|
||||||
|
if (!this.account) return ''
|
||||||
|
|
||||||
|
return this.account.avatarUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
hasRight (right: UserRight) {
|
hasRight (right: UserRight) {
|
||||||
|
@ -81,17 +84,9 @@ export class User implements UserServerModel {
|
||||||
if (obj.account !== undefined) {
|
if (obj.account !== undefined) {
|
||||||
this.account = new Account(obj.account)
|
this.account = new Account(obj.account)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateComputedAttributes()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAccountAvatar (newAccountAvatar: Avatar) {
|
updateAccountAvatar (newAccountAvatar: Avatar) {
|
||||||
this.account.avatar = newAccountAvatar
|
this.account.updateAvatar(newAccountAvatar)
|
||||||
|
|
||||||
this.updateComputedAttributes()
|
|
||||||
}
|
|
||||||
|
|
||||||
private updateComputedAttributes () {
|
|
||||||
this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { ResultList } from '../../../../../shared'
|
||||||
import { VideoChannel } from './video-channel.model'
|
import { VideoChannel } from './video-channel.model'
|
||||||
import { environment } from '../../../environments/environment'
|
import { environment } from '../../../environments/environment'
|
||||||
import { Account } from '@app/shared/account/account.model'
|
import { Account } from '@app/shared/account/account.model'
|
||||||
|
import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class VideoChannelService {
|
export class VideoChannelService {
|
||||||
|
@ -54,6 +55,13 @@ export class VideoChannelService {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeVideoChannelAvatar (videoChannelUUID: string, avatarForm: FormData) {
|
||||||
|
const url = VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelUUID + '/avatar/pick'
|
||||||
|
|
||||||
|
return this.authHttp.post<{ avatar: Avatar }>(url, avatarForm)
|
||||||
|
.pipe(catchError(this.restExtractor.handleError))
|
||||||
|
}
|
||||||
|
|
||||||
removeVideoChannel (videoChannel: VideoChannel) {
|
removeVideoChannel (videoChannel: VideoChannel) {
|
||||||
return this.authHttp.delete(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid)
|
return this.authHttp.delete(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid)
|
||||||
.pipe(
|
.pipe(
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { VideoScheduleUpdate } from '../../../../../shared/models/videos/video-s
|
||||||
export class Video implements VideoServerModel {
|
export class Video implements VideoServerModel {
|
||||||
by: string
|
by: string
|
||||||
accountAvatarUrl: string
|
accountAvatarUrl: string
|
||||||
|
videoChannelAvatarUrl: string
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
updatedAt: Date
|
updatedAt: Date
|
||||||
publishedAt: Date
|
publishedAt: Date
|
||||||
|
@ -102,9 +103,11 @@ export class Video implements VideoServerModel {
|
||||||
this.dislikes = hash.dislikes
|
this.dislikes = hash.dislikes
|
||||||
this.nsfw = hash.nsfw
|
this.nsfw = hash.nsfw
|
||||||
this.account = hash.account
|
this.account = hash.account
|
||||||
|
this.channel = hash.channel
|
||||||
|
|
||||||
this.by = Actor.CREATE_BY_STRING(hash.account.name, hash.account.host)
|
this.by = Actor.CREATE_BY_STRING(hash.account.name, hash.account.host)
|
||||||
this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account)
|
this.accountAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.account)
|
||||||
|
this.videoChannelAvatarUrl = Actor.GET_ACTOR_AVATAR_URL(this.channel)
|
||||||
|
|
||||||
this.category.label = peertubeTranslate(this.category.label, translations)
|
this.category.label = peertubeTranslate(this.category.label, translations)
|
||||||
this.licence.label = peertubeTranslate(this.licence.label, translations)
|
this.licence.label = peertubeTranslate(this.licence.label, translations)
|
||||||
|
|
|
@ -132,10 +132,10 @@ export class VideoAddComponent extends FormReactive implements OnInit, OnDestroy
|
||||||
if (!videofile) return
|
if (!videofile) return
|
||||||
|
|
||||||
// Cannot upload videos > 4GB for now
|
// Cannot upload videos > 4GB for now
|
||||||
if (videofile.size > 4 * 1024 * 1024 * 1024) {
|
// if (videofile.size > 4 * 1024 * 1024 * 1024) {
|
||||||
this.notificationsService.error(this.i18n('Error'), this.i18n('We are sorry but PeerTube cannot handle videos > 4GB'))
|
// this.notificationsService.error(this.i18n('Error'), this.i18n('We are sorry but PeerTube cannot handle videos > 4GB'))
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
const videoQuota = this.authService.getUser().videoQuota
|
const videoQuota = this.authService.getUser().videoQuota
|
||||||
if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) {
|
if (videoQuota !== -1 && (this.userVideoQuotaUsed + videofile.size) > videoQuota) {
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
<div class="video-info-channel">
|
<div class="video-info-channel">
|
||||||
<a [routerLink]="[ '/video-channels', video.channel.id ]" i18n-title title="Go the channel page">
|
<a [routerLink]="[ '/video-channels', video.channel.id ]" i18n-title title="Go the channel page">
|
||||||
{{ video.channel.displayName }}
|
{{ video.channel.displayName }}
|
||||||
|
|
||||||
|
<img [src]="video.videoChannelAvatarUrl" alt="Video channel avatar" />
|
||||||
</a>
|
</a>
|
||||||
<!-- Here will be the subscribe button -->
|
<!-- Here will be the subscribe button -->
|
||||||
<my-help helpType="custom" i18n-customHtml customHtml="You can subscribe to this account via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type in the search box <strong>@{{video.account.name}}@{{video.account.host}}</strong> and subscribe there. Subscription as a PeerTube user is being worked on in <a href='https://github.com/Chocobozzz/PeerTube/issues/470'>#470</a>."></my-help>
|
<my-help helpType="custom" i18n-customHtml customHtml="You can subscribe to this account via any ActivityPub-capable fediverse instance. For instance with Mastodon or Pleroma you can type in the search box <strong>@{{video.account.name}}@{{video.account.host}}</strong> and subscribe there. Subscription as a PeerTube user is being worked on in <a href='https://github.com/Chocobozzz/PeerTube/issues/470'>#470</a>."></my-help>
|
||||||
|
|
|
@ -84,6 +84,12 @@
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
@include avatar(18px);
|
||||||
|
|
||||||
|
margin: -2px 2px 0 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my-help {
|
my-help {
|
||||||
|
@ -106,6 +112,7 @@
|
||||||
img {
|
img {
|
||||||
@include avatar(18px);
|
@include avatar(18px);
|
||||||
|
|
||||||
|
margin-top: -2px;
|
||||||
margin-left: 7px;
|
margin-left: 7px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,6 +251,10 @@ export enum ScopeNames {
|
||||||
attributes: [ 'host' ],
|
attributes: [ 'host' ],
|
||||||
model: () => ServerModel.unscoped(),
|
model: () => ServerModel.unscoped(),
|
||||||
required: false
|
required: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: () => AvatarModel.unscoped(),
|
||||||
|
required: false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -14,7 +14,8 @@ import {
|
||||||
killallServers,
|
killallServers,
|
||||||
makeGetRequest,
|
makeGetRequest,
|
||||||
makePostBodyRequest,
|
makePostBodyRequest,
|
||||||
makePutBodyRequest, makeUploadRequest,
|
makePutBodyRequest,
|
||||||
|
makeUploadRequest,
|
||||||
runServer,
|
runServer,
|
||||||
ServerInfo,
|
ServerInfo,
|
||||||
setAccessTokensToServers,
|
setAccessTokensToServers,
|
||||||
|
@ -22,7 +23,7 @@ import {
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params'
|
import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params'
|
||||||
import { User } from '../../../../shared/models/users'
|
import { User } from '../../../../shared/models/users'
|
||||||
import { join } from "path"
|
import { join } from 'path'
|
||||||
|
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue