diff options
author | Chocobozzz <me@florianbigard.com> | 2018-04-25 16:56:13 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-04-25 16:56:13 +0200 |
commit | 170726f523ff48f89da45473fc53ca54784f43dd (patch) | |
tree | f9f783ebdfc934c6831396c2bf33f658d6640583 | |
parent | cc918ac3f45e32f031cce7b6e0473e5c2c34b8ae (diff) | |
download | PeerTube-170726f523ff48f89da45473fc53ca54784f43dd.tar.gz PeerTube-170726f523ff48f89da45473fc53ca54784f43dd.tar.zst PeerTube-170726f523ff48f89da45473fc53ca54784f43dd.zip |
Implement video channel views
35 files changed, 375 insertions, 83 deletions
diff --git a/client/src/app/+account/account.component.scss b/client/src/app/+account/account.component.scss deleted file mode 100644 index c7b8f038f..000000000 --- a/client/src/app/+account/account.component.scss +++ /dev/null | |||
@@ -1,46 +0,0 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .sub-menu { | ||
5 | height: 160px; | ||
6 | display: flex; | ||
7 | flex-direction: column; | ||
8 | align-items: start; | ||
9 | |||
10 | .account { | ||
11 | display: flex; | ||
12 | margin-top: 20px; | ||
13 | margin-bottom: 20px; | ||
14 | |||
15 | img { | ||
16 | @include avatar(80px); | ||
17 | |||
18 | margin-right: 20px; | ||
19 | } | ||
20 | |||
21 | .account-info { | ||
22 | display: flex; | ||
23 | flex-direction: column; | ||
24 | justify-content: center; | ||
25 | |||
26 | .account-display-name { | ||
27 | font-size: 23px; | ||
28 | font-weight: $font-bold; | ||
29 | } | ||
30 | |||
31 | .account-followers { | ||
32 | font-size: 15px; | ||
33 | } | ||
34 | } | ||
35 | } | ||
36 | |||
37 | .links { | ||
38 | margin-top: 0; | ||
39 | margin-bottom: 10px; | ||
40 | |||
41 | a { | ||
42 | margin-top: 0; | ||
43 | margin-bottom: 0; | ||
44 | } | ||
45 | } | ||
46 | } \ No newline at end of file | ||
diff --git a/client/src/app/+account/index.ts b/client/src/app/+account/index.ts deleted file mode 100644 index dc56ffdbd..000000000 --- a/client/src/app/+account/index.ts +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | export * from './account-routing.module' | ||
2 | export * from './account.component' | ||
3 | export * from './account.module' | ||
diff --git a/client/src/app/+account/account-about/account-about.component.html b/client/src/app/+accounts/account-about/account-about.component.html index 003a8045e..003a8045e 100644 --- a/client/src/app/+account/account-about/account-about.component.html +++ b/client/src/app/+accounts/account-about/account-about.component.html | |||
diff --git a/client/src/app/+account/account-about/account-about.component.scss b/client/src/app/+accounts/account-about/account-about.component.scss index b1be7d4ed..b1be7d4ed 100644 --- a/client/src/app/+account/account-about/account-about.component.scss +++ b/client/src/app/+accounts/account-about/account-about.component.scss | |||
diff --git a/client/src/app/+account/account-about/account-about.component.ts b/client/src/app/+accounts/account-about/account-about.component.ts index 8746875cb..8746875cb 100644 --- a/client/src/app/+account/account-about/account-about.component.ts +++ b/client/src/app/+accounts/account-about/account-about.component.ts | |||
diff --git a/client/src/app/+account/account-video-channels/account-video-channels.component.html b/client/src/app/+accounts/account-video-channels/account-video-channels.component.html index d20b40c60..d20b40c60 100644 --- a/client/src/app/+account/account-video-channels/account-video-channels.component.html +++ b/client/src/app/+accounts/account-video-channels/account-video-channels.component.html | |||
diff --git a/client/src/app/+account/account-video-channels/account-video-channels.component.scss b/client/src/app/+accounts/account-video-channels/account-video-channels.component.scss index c9c7fa8eb..c9c7fa8eb 100644 --- a/client/src/app/+account/account-video-channels/account-video-channels.component.scss +++ b/client/src/app/+accounts/account-video-channels/account-video-channels.component.scss | |||
diff --git a/client/src/app/+account/account-video-channels/account-video-channels.component.ts b/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts index 8915eb622..4c5782f9d 100644 --- a/client/src/app/+account/account-video-channels/account-video-channels.component.ts +++ b/client/src/app/+accounts/account-video-channels/account-video-channels.component.ts | |||
@@ -26,7 +26,7 @@ export class AccountVideoChannelsComponent implements OnInit { | |||
26 | // Parent get the account for us | 26 | // Parent get the account for us |
27 | this.accountService.accountLoaded | 27 | this.accountService.accountLoaded |
28 | .do(account => this.account = account) | 28 | .do(account => this.account = account) |
29 | .flatMap(account => this.videoChannelService.getVideoChannels(account.id)) | 29 | .flatMap(account => this.videoChannelService.listAccountVideoChannels(account.id)) |
30 | .map(res => res.data) | 30 | .map(res => res.data) |
31 | .subscribe(videoChannels => this.videoChannels = videoChannels) | 31 | .subscribe(videoChannels => this.videoChannels = videoChannels) |
32 | } | 32 | } |
diff --git a/client/src/app/+account/account-videos/account-videos.component.scss b/client/src/app/+accounts/account-videos/account-videos.component.scss index 2ba85c031..2ba85c031 100644 --- a/client/src/app/+account/account-videos/account-videos.component.scss +++ b/client/src/app/+accounts/account-videos/account-videos.component.scss | |||
diff --git a/client/src/app/+account/account-videos/account-videos.component.ts b/client/src/app/+accounts/account-videos/account-videos.component.ts index 6c0f0bb52..6c0f0bb52 100644 --- a/client/src/app/+account/account-videos/account-videos.component.ts +++ b/client/src/app/+accounts/account-videos/account-videos.component.ts | |||
diff --git a/client/src/app/+account/account-routing.module.ts b/client/src/app/+accounts/accounts-routing.module.ts index f72d8373f..ffe606b43 100644 --- a/client/src/app/+account/account-routing.module.ts +++ b/client/src/app/+accounts/accounts-routing.module.ts | |||
@@ -1,15 +1,15 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router' | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | import { MetaGuard } from '@ngx-meta/core' | 3 | import { MetaGuard } from '@ngx-meta/core' |
4 | import { AccountComponent } from './account.component' | 4 | import { AccountsComponent } from './accounts.component' |
5 | import { AccountVideosComponent } from './account-videos/account-videos.component' | 5 | import { AccountVideosComponent } from './account-videos/account-videos.component' |
6 | import { AccountAboutComponent } from './account-about/account-about.component' | 6 | import { AccountAboutComponent } from './account-about/account-about.component' |
7 | import { AccountVideoChannelsComponent } from './account-video-channels/account-video-channels.component' | 7 | import { AccountVideoChannelsComponent } from './account-video-channels/account-video-channels.component' |
8 | 8 | ||
9 | const accountRoutes: Routes = [ | 9 | const accountsRoutes: Routes = [ |
10 | { | 10 | { |
11 | path: ':accountId', | 11 | path: ':accountId', |
12 | component: AccountComponent, | 12 | component: AccountsComponent, |
13 | canActivateChild: [ MetaGuard ], | 13 | canActivateChild: [ MetaGuard ], |
14 | children: [ | 14 | children: [ |
15 | { | 15 | { |
@@ -49,7 +49,7 @@ const accountRoutes: Routes = [ | |||
49 | ] | 49 | ] |
50 | 50 | ||
51 | @NgModule({ | 51 | @NgModule({ |
52 | imports: [ RouterModule.forChild(accountRoutes) ], | 52 | imports: [ RouterModule.forChild(accountsRoutes) ], |
53 | exports: [ RouterModule ] | 53 | exports: [ RouterModule ] |
54 | }) | 54 | }) |
55 | export class AccountRoutingModule {} | 55 | export class AccountsRoutingModule {} |
diff --git a/client/src/app/+account/account.component.html b/client/src/app/+accounts/accounts.component.html index d0e99edda..549676e5a 100644 --- a/client/src/app/+account/account.component.html +++ b/client/src/app/+accounts/accounts.component.html | |||
@@ -1,12 +1,12 @@ | |||
1 | <div *ngIf="account" class="row"> | 1 | <div *ngIf="account" class="row"> |
2 | <div class="sub-menu"> | 2 | <div class="sub-menu"> |
3 | 3 | ||
4 | <div class="account"> | 4 | <div class="actor"> |
5 | <img [src]="account.avatarUrl" alt="Avatar" /> | 5 | <img [src]="account.avatarUrl" alt="Avatar" /> |
6 | 6 | ||
7 | <div class="account-info"> | 7 | <div class="actor-info"> |
8 | <div class="account-display-name">{{ account.displayName }}</div> | 8 | <div class="actor-display-name">{{ account.displayName }}</div> |
9 | <div class="account-followers">{{ account.followersCount }} subscribers</div> | 9 | <div class="actor-followers">{{ account.followersCount }} subscribers</div> |
10 | </div> | 10 | </div> |
11 | </div> | 11 | </div> |
12 | 12 | ||
diff --git a/client/src/app/+accounts/accounts.component.scss b/client/src/app/+accounts/accounts.component.scss new file mode 100644 index 000000000..909b65bc7 --- /dev/null +++ b/client/src/app/+accounts/accounts.component.scss | |||
@@ -0,0 +1,6 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .sub-menu { | ||
5 | @include sub-menu-with-actor; | ||
6 | } \ No newline at end of file | ||
diff --git a/client/src/app/+account/account.component.ts b/client/src/app/+accounts/accounts.component.ts index d936ce2fe..1298803c3 100644 --- a/client/src/app/+account/account.component.ts +++ b/client/src/app/+accounts/accounts.component.ts | |||
@@ -4,11 +4,10 @@ import { AccountService } from '@app/shared/account/account.service' | |||
4 | import { Account } from '@app/shared/account/account.model' | 4 | import { Account } from '@app/shared/account/account.model' |
5 | 5 | ||
6 | @Component({ | 6 | @Component({ |
7 | selector: 'my-account', | 7 | templateUrl: './accounts.component.html', |
8 | templateUrl: './account.component.html', | 8 | styleUrls: [ './accounts.component.scss' ] |
9 | styleUrls: [ './account.component.scss' ] | ||
10 | }) | 9 | }) |
11 | export class AccountComponent implements OnInit { | 10 | export class AccountsComponent implements OnInit { |
12 | account: Account | 11 | account: Account |
13 | 12 | ||
14 | constructor ( | 13 | constructor ( |
diff --git a/client/src/app/+account/account.module.ts b/client/src/app/+accounts/accounts.module.ts index 82ef06e76..8e679822a 100644 --- a/client/src/app/+account/account.module.ts +++ b/client/src/app/+accounts/accounts.module.ts | |||
@@ -1,28 +1,28 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { SharedModule } from '../shared' | 2 | import { SharedModule } from '../shared' |
3 | import { AccountRoutingModule } from './account-routing.module' | 3 | import { AccountsRoutingModule } from './accounts-routing.module' |
4 | import { AccountComponent } from './account.component' | 4 | import { AccountsComponent } from './accounts.component' |
5 | import { AccountVideosComponent } from './account-videos/account-videos.component' | 5 | import { AccountVideosComponent } from './account-videos/account-videos.component' |
6 | import { AccountAboutComponent } from './account-about/account-about.component' | 6 | import { AccountAboutComponent } from './account-about/account-about.component' |
7 | import { AccountVideoChannelsComponent } from './account-video-channels/account-video-channels.component' | 7 | import { AccountVideoChannelsComponent } from './account-video-channels/account-video-channels.component' |
8 | 8 | ||
9 | @NgModule({ | 9 | @NgModule({ |
10 | imports: [ | 10 | imports: [ |
11 | AccountRoutingModule, | 11 | AccountsRoutingModule, |
12 | SharedModule | 12 | SharedModule |
13 | ], | 13 | ], |
14 | 14 | ||
15 | declarations: [ | 15 | declarations: [ |
16 | AccountComponent, | 16 | AccountsComponent, |
17 | AccountVideosComponent, | 17 | AccountVideosComponent, |
18 | AccountVideoChannelsComponent, | 18 | AccountVideoChannelsComponent, |
19 | AccountAboutComponent | 19 | AccountAboutComponent |
20 | ], | 20 | ], |
21 | 21 | ||
22 | exports: [ | 22 | exports: [ |
23 | AccountComponent | 23 | AccountsComponent |
24 | ], | 24 | ], |
25 | 25 | ||
26 | providers: [] | 26 | providers: [] |
27 | }) | 27 | }) |
28 | export class AccountModule { } | 28 | export class AccountsModule { } |
diff --git a/client/src/app/+accounts/index.ts b/client/src/app/+accounts/index.ts new file mode 100644 index 000000000..4dfb6f586 --- /dev/null +++ b/client/src/app/+accounts/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './accounts-routing.module' | ||
2 | export * from './accounts.component' | ||
3 | export * from './accounts.module' | ||
diff --git a/client/src/app/+video-channels/index.ts b/client/src/app/+video-channels/index.ts new file mode 100644 index 000000000..6683d1b12 --- /dev/null +++ b/client/src/app/+video-channels/index.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export * from './video-channels-routing.module' | ||
2 | export * from './video-channels.component' | ||
3 | export * from './video-channels.module' | ||
diff --git a/client/src/app/+video-channels/video-channel-about/video-channel-about.component.html b/client/src/app/+video-channels/video-channel-about/video-channel-about.component.html new file mode 100644 index 000000000..65ad6f541 --- /dev/null +++ b/client/src/app/+video-channels/video-channel-about/video-channel-about.component.html | |||
@@ -0,0 +1,12 @@ | |||
1 | <div *ngIf="videoChannel" class="row"> | ||
2 | <div class="description col-md-6 col-sm-12"> | ||
3 | <div class="small-title">Description</div> | ||
4 | <div class="content">{{ getVideoChannelDescription() }}</div> | ||
5 | </div> | ||
6 | |||
7 | <div class="stats col-md-6 col-sm-12"> | ||
8 | <div class="small-title">Stats</div> | ||
9 | |||
10 | <div class="content">Created {{ videoChannel.createdAt | date }}</div> | ||
11 | </div> | ||
12 | </div> \ No newline at end of file | ||
diff --git a/client/src/app/+video-channels/video-channel-about/video-channel-about.component.scss b/client/src/app/+video-channels/video-channel-about/video-channel-about.component.scss new file mode 100644 index 000000000..b1be7d4ed --- /dev/null +++ b/client/src/app/+video-channels/video-channel-about/video-channel-about.component.scss | |||
@@ -0,0 +1,8 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .small-title { | ||
5 | @include in-content-small-title; | ||
6 | |||
7 | margin-bottom: 20px; | ||
8 | } | ||
diff --git a/client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts b/client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts new file mode 100644 index 000000000..5d435708e --- /dev/null +++ b/client/src/app/+video-channels/video-channel-about/video-channel-about.component.ts | |||
@@ -0,0 +1,32 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { ActivatedRoute } from '@angular/router' | ||
3 | import 'rxjs/add/observable/from' | ||
4 | import 'rxjs/add/operator/concatAll' | ||
5 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' | ||
6 | import { VideoChannel } from '@app/shared/video-channel/video-channel.model' | ||
7 | |||
8 | @Component({ | ||
9 | selector: 'my-video-channel-about', | ||
10 | templateUrl: './video-channel-about.component.html', | ||
11 | styleUrls: [ './video-channel-about.component.scss' ] | ||
12 | }) | ||
13 | export class VideoChannelAboutComponent implements OnInit { | ||
14 | videoChannel: VideoChannel | ||
15 | |||
16 | constructor ( | ||
17 | protected route: ActivatedRoute, | ||
18 | private videoChannelService: VideoChannelService | ||
19 | ) { } | ||
20 | |||
21 | ngOnInit () { | ||
22 | // Parent get the video channel for us | ||
23 | this.videoChannelService.videoChannelLoaded | ||
24 | .subscribe(videoChannel => this.videoChannel = videoChannel) | ||
25 | } | ||
26 | |||
27 | getVideoChannelDescription () { | ||
28 | if (this.videoChannel.description) return this.videoChannel.description | ||
29 | |||
30 | return 'No description' | ||
31 | } | ||
32 | } | ||
diff --git a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.scss b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.scss new file mode 100644 index 000000000..2ba85c031 --- /dev/null +++ b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.scss | |||
@@ -0,0 +1,3 @@ | |||
1 | .title-page-single { | ||
2 | margin-top: 0; | ||
3 | } \ No newline at end of file | ||
diff --git a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts new file mode 100644 index 000000000..3cda630d3 --- /dev/null +++ b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts | |||
@@ -0,0 +1,71 @@ | |||
1 | import { Component, OnDestroy, OnInit } from '@angular/core' | ||
2 | import { ActivatedRoute, Router } from '@angular/router' | ||
3 | import { Location } from '@angular/common' | ||
4 | import { immutableAssign } from '@app/shared/misc/utils' | ||
5 | import { NotificationsService } from 'angular2-notifications' | ||
6 | import 'rxjs/add/observable/from' | ||
7 | import 'rxjs/add/operator/concatAll' | ||
8 | import { AuthService } from '../../core/auth' | ||
9 | import { ConfirmService } from '../../core/confirm' | ||
10 | import { AbstractVideoList } from '../../shared/video/abstract-video-list' | ||
11 | import { VideoService } from '../../shared/video/video.service' | ||
12 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' | ||
13 | import { VideoChannel } from '@app/shared/video-channel/video-channel.model' | ||
14 | |||
15 | @Component({ | ||
16 | selector: 'my-video-channel-videos', | ||
17 | templateUrl: '../../shared/video/abstract-video-list.html', | ||
18 | styleUrls: [ | ||
19 | '../../shared/video/abstract-video-list.scss', | ||
20 | './video-channel-videos.component.scss' | ||
21 | ] | ||
22 | }) | ||
23 | export class VideoChannelVideosComponent extends AbstractVideoList implements OnInit, OnDestroy { | ||
24 | titlePage = 'Published videos' | ||
25 | marginContent = false // Disable margin | ||
26 | currentRoute = '/video-channel/videos' | ||
27 | loadOnInit = false | ||
28 | |||
29 | private videoChannel: VideoChannel | ||
30 | |||
31 | constructor ( | ||
32 | protected router: Router, | ||
33 | protected route: ActivatedRoute, | ||
34 | protected authService: AuthService, | ||
35 | protected notificationsService: NotificationsService, | ||
36 | protected confirmService: ConfirmService, | ||
37 | protected location: Location, | ||
38 | private videoChannelService: VideoChannelService, | ||
39 | private videoService: VideoService | ||
40 | ) { | ||
41 | super() | ||
42 | } | ||
43 | |||
44 | ngOnInit () { | ||
45 | super.ngOnInit() | ||
46 | |||
47 | // Parent get the video channel for us | ||
48 | this.videoChannelService.videoChannelLoaded | ||
49 | .subscribe(videoChannel => { | ||
50 | this.videoChannel = videoChannel | ||
51 | this.currentRoute = '/video-channel/' + this.videoChannel.uuid + '/videos' | ||
52 | |||
53 | this.loadMoreVideos(this.pagination.currentPage) | ||
54 | this.generateSyndicationList() | ||
55 | }) | ||
56 | } | ||
57 | |||
58 | ngOnDestroy () { | ||
59 | super.ngOnDestroy() | ||
60 | } | ||
61 | |||
62 | getVideosObservable (page: number) { | ||
63 | const newPagination = immutableAssign(this.pagination, { currentPage: page }) | ||
64 | |||
65 | return this.videoService.getVideoChannelVideos(this.videoChannel, newPagination, this.sort) | ||
66 | } | ||
67 | |||
68 | generateSyndicationList () { | ||
69 | this.syndicationItems = this.videoService.getVideoChannelFeedUrls(this.videoChannel.id) | ||
70 | } | ||
71 | } | ||
diff --git a/client/src/app/+video-channels/video-channels-routing.module.ts b/client/src/app/+video-channels/video-channels-routing.module.ts new file mode 100644 index 000000000..935578d2a --- /dev/null +++ b/client/src/app/+video-channels/video-channels-routing.module.ts | |||
@@ -0,0 +1,45 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | import { RouterModule, Routes } from '@angular/router' | ||
3 | import { MetaGuard } from '@ngx-meta/core' | ||
4 | import { VideoChannelsComponent } from './video-channels.component' | ||
5 | import { VideoChannelVideosComponent } from './video-channel-videos/video-channel-videos.component' | ||
6 | import { VideoChannelAboutComponent } from './video-channel-about/video-channel-about.component' | ||
7 | |||
8 | const videoChannelsRoutes: Routes = [ | ||
9 | { | ||
10 | path: ':videoChannelId', | ||
11 | component: VideoChannelsComponent, | ||
12 | canActivateChild: [ MetaGuard ], | ||
13 | children: [ | ||
14 | { | ||
15 | path: '', | ||
16 | redirectTo: 'videos', | ||
17 | pathMatch: 'full' | ||
18 | }, | ||
19 | { | ||
20 | path: 'videos', | ||
21 | component: VideoChannelVideosComponent, | ||
22 | data: { | ||
23 | meta: { | ||
24 | title: 'Video channel videos' | ||
25 | } | ||
26 | } | ||
27 | }, | ||
28 | { | ||
29 | path: 'about', | ||
30 | component: VideoChannelAboutComponent, | ||
31 | data: { | ||
32 | meta: { | ||
33 | title: 'About video channel' | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | ] | ||
38 | } | ||
39 | ] | ||
40 | |||
41 | @NgModule({ | ||
42 | imports: [ RouterModule.forChild(videoChannelsRoutes) ], | ||
43 | exports: [ RouterModule ] | ||
44 | }) | ||
45 | export class VideoChannelsRoutingModule {} | ||
diff --git a/client/src/app/+video-channels/video-channels.component.html b/client/src/app/+video-channels/video-channels.component.html new file mode 100644 index 000000000..098e1eed4 --- /dev/null +++ b/client/src/app/+video-channels/video-channels.component.html | |||
@@ -0,0 +1,23 @@ | |||
1 | <div *ngIf="videoChannel" class="row"> | ||
2 | <div class="sub-menu"> | ||
3 | |||
4 | <div class="actor"> | ||
5 | <img [src]="videoChannel.avatarUrl" alt="Avatar" /> | ||
6 | |||
7 | <div class="actor-info"> | ||
8 | <div class="actor-display-name">{{ videoChannel.displayName }}</div> | ||
9 | <div class="actor-followers">{{ videoChannel.followersCount }} subscribers</div> | ||
10 | </div> | ||
11 | </div> | ||
12 | |||
13 | <div class="links"> | ||
14 | <a routerLink="videos" routerLinkActive="active" class="title-page">Videos</a> | ||
15 | |||
16 | <a routerLink="about" routerLinkActive="active" class="title-page">About</a> | ||
17 | </div> | ||
18 | </div> | ||
19 | |||
20 | <div class="margin-content"> | ||
21 | <router-outlet></router-outlet> | ||
22 | </div> | ||
23 | </div> | ||
diff --git a/client/src/app/+video-channels/video-channels.component.scss b/client/src/app/+video-channels/video-channels.component.scss new file mode 100644 index 000000000..909b65bc7 --- /dev/null +++ b/client/src/app/+video-channels/video-channels.component.scss | |||
@@ -0,0 +1,6 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .sub-menu { | ||
5 | @include sub-menu-with-actor; | ||
6 | } \ No newline at end of file | ||
diff --git a/client/src/app/+video-channels/video-channels.component.ts b/client/src/app/+video-channels/video-channels.component.ts new file mode 100644 index 000000000..5eca64fb5 --- /dev/null +++ b/client/src/app/+video-channels/video-channels.component.ts | |||
@@ -0,0 +1,24 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { ActivatedRoute } from '@angular/router' | ||
3 | import { VideoChannel } from '@app/shared/video-channel/video-channel.model' | ||
4 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' | ||
5 | |||
6 | @Component({ | ||
7 | templateUrl: './video-channels.component.html', | ||
8 | styleUrls: [ './video-channels.component.scss' ] | ||
9 | }) | ||
10 | export class VideoChannelsComponent implements OnInit { | ||
11 | videoChannel: VideoChannel | ||
12 | |||
13 | constructor ( | ||
14 | private route: ActivatedRoute, | ||
15 | private videoChannelService: VideoChannelService | ||
16 | ) {} | ||
17 | |||
18 | ngOnInit () { | ||
19 | const videoChannelId = this.route.snapshot.params['videoChannelId'] | ||
20 | |||
21 | this.videoChannelService.getVideoChannel(videoChannelId) | ||
22 | .subscribe(videoChannel => this.videoChannel = videoChannel) | ||
23 | } | ||
24 | } | ||
diff --git a/client/src/app/+video-channels/video-channels.module.ts b/client/src/app/+video-channels/video-channels.module.ts new file mode 100644 index 000000000..a09ea6f11 --- /dev/null +++ b/client/src/app/+video-channels/video-channels.module.ts | |||
@@ -0,0 +1,26 @@ | |||
1 | import { NgModule } from '@angular/core' | ||
2 | import { SharedModule } from '../shared' | ||
3 | import { VideoChannelsRoutingModule } from './video-channels-routing.module' | ||
4 | import { VideoChannelsComponent } from './video-channels.component' | ||
5 | import { VideoChannelVideosComponent } from './video-channel-videos/video-channel-videos.component' | ||
6 | import { VideoChannelAboutComponent } from './video-channel-about/video-channel-about.component' | ||
7 | |||
8 | @NgModule({ | ||
9 | imports: [ | ||
10 | VideoChannelsRoutingModule, | ||
11 | SharedModule | ||
12 | ], | ||
13 | |||
14 | declarations: [ | ||
15 | VideoChannelsComponent, | ||
16 | VideoChannelVideosComponent, | ||
17 | VideoChannelAboutComponent | ||
18 | ], | ||
19 | |||
20 | exports: [ | ||
21 | VideoChannelsComponent | ||
22 | ], | ||
23 | |||
24 | providers: [] | ||
25 | }) | ||
26 | export class VideoChannelsModule { } | ||
diff --git a/client/src/app/app-routing.module.ts b/client/src/app/app-routing.module.ts index 1d55b4cea..799748cfa 100644 --- a/client/src/app/app-routing.module.ts +++ b/client/src/app/app-routing.module.ts | |||
@@ -9,8 +9,12 @@ const routes: Routes = [ | |||
9 | loadChildren: './+admin/admin.module#AdminModule' | 9 | loadChildren: './+admin/admin.module#AdminModule' |
10 | }, | 10 | }, |
11 | { | 11 | { |
12 | path: 'account', | 12 | path: 'accounts', |
13 | loadChildren: './+account/account.module#AccountModule' | 13 | loadChildren: './+accounts/accounts.module#AccountsModule' |
14 | }, | ||
15 | { | ||
16 | path: 'video-channels', | ||
17 | loadChildren: './+video-channels/video-channels.module#VideoChannelsModule' | ||
14 | } | 18 | } |
15 | ] | 19 | ] |
16 | 20 | ||
diff --git a/client/src/app/shared/video-channel/video-channel.service.ts b/client/src/app/shared/video-channel/video-channel.service.ts index 1f9088c38..d8efcc171 100644 --- a/client/src/app/shared/video-channel/video-channel.service.ts +++ b/client/src/app/shared/video-channel/video-channel.service.ts | |||
@@ -9,16 +9,29 @@ import { VideoChannel as VideoChannelServer } from '../../../../../shared/models | |||
9 | import { AccountService } from '../account/account.service' | 9 | import { AccountService } from '../account/account.service' |
10 | import { ResultList } from '../../../../../shared' | 10 | import { ResultList } from '../../../../../shared' |
11 | import { VideoChannel } from './video-channel.model' | 11 | import { VideoChannel } from './video-channel.model' |
12 | import { ReplaySubject } from 'rxjs/ReplaySubject' | ||
13 | import { environment } from '../../../environments/environment' | ||
12 | 14 | ||
13 | @Injectable() | 15 | @Injectable() |
14 | export class VideoChannelService { | 16 | export class VideoChannelService { |
17 | static BASE_VIDEO_CHANNEL_URL = environment.apiUrl + '/api/v1/video-channels/' | ||
18 | |||
19 | videoChannelLoaded = new ReplaySubject<VideoChannel>(1) | ||
20 | |||
15 | constructor ( | 21 | constructor ( |
16 | private authHttp: HttpClient, | 22 | private authHttp: HttpClient, |
17 | private restExtractor: RestExtractor, | 23 | private restExtractor: RestExtractor, |
18 | private restService: RestService | 24 | private restService: RestService |
19 | ) {} | 25 | ) {} |
20 | 26 | ||
21 | getVideoChannels (accountId: number): Observable<ResultList<VideoChannel>> { | 27 | getVideoChannel (videoChannelUUID: string) { |
28 | return this.authHttp.get<VideoChannel>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannelUUID) | ||
29 | .map(videoChannelHash => new VideoChannel(videoChannelHash)) | ||
30 | .do(videoChannel => this.videoChannelLoaded.next(videoChannel)) | ||
31 | .catch((res) => this.restExtractor.handleError(res)) | ||
32 | } | ||
33 | |||
34 | listAccountVideoChannels (accountId: number): Observable<ResultList<VideoChannel>> { | ||
22 | return this.authHttp.get<ResultList<VideoChannelServer>>(AccountService.BASE_ACCOUNT_URL + accountId + '/video-channels') | 35 | return this.authHttp.get<ResultList<VideoChannelServer>>(AccountService.BASE_ACCOUNT_URL + accountId + '/video-channels') |
23 | .map(res => this.extractVideoChannels(res)) | 36 | .map(res => this.extractVideoChannels(res)) |
24 | .catch((res) => this.restExtractor.handleError(res)) | 37 | .catch((res) => this.restExtractor.handleError(res)) |
diff --git a/client/src/app/shared/video/video-miniature.component.html b/client/src/app/shared/video/video-miniature.component.html index d0b305509..e26cb058a 100644 --- a/client/src/app/shared/video/video-miniature.component.html +++ b/client/src/app/shared/video/video-miniature.component.html | |||
@@ -5,13 +5,13 @@ | |||
5 | <span class="video-miniature-name"> | 5 | <span class="video-miniature-name"> |
6 | <a | 6 | <a |
7 | class="video-miniature-name" | 7 | class="video-miniature-name" |
8 | [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name" [ngClass]="{ 'blur-filter': isVideoBlur() }" | 8 | [routerLink]="[ '/videos/watch', video.uuid ]" [attr.title]="video.name" [ngClass]="{ 'blur-filter': isVideoBlur() }" |
9 | > | 9 | > |
10 | {{ video.name }} | 10 | {{ video.name }} |
11 | </a> | 11 | </a> |
12 | </span> | 12 | </span> |
13 | 13 | ||
14 | <span class="video-miniature-created-at-views">{{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span> | 14 | <span class="video-miniature-created-at-views">{{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span> |
15 | <a class="video-miniature-account" [routerLink]="[ '/account', video.account.id ]">{{ video.by }}</a> | 15 | <a class="video-miniature-account" [routerLink]="[ '/accounts', video.account.id ]">{{ video.by }}</a> |
16 | </div> | 16 | </div> |
17 | </div> | 17 | </div> |
diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts index f82aa7389..8870cbee4 100644 --- a/client/src/app/shared/video/video.service.ts +++ b/client/src/app/shared/video/video.service.ts | |||
@@ -23,6 +23,8 @@ import { Video } from './video.model' | |||
23 | import { objectToFormData } from '@app/shared/misc/utils' | 23 | import { objectToFormData } from '@app/shared/misc/utils' |
24 | import { Account } from '@app/shared/account/account.model' | 24 | import { Account } from '@app/shared/account/account.model' |
25 | import { AccountService } from '@app/shared/account/account.service' | 25 | import { AccountService } from '@app/shared/account/account.service' |
26 | import { VideoChannel } from '../../../../../shared/models/videos' | ||
27 | import { VideoChannelService } from '@app/shared/video-channel/video-channel.service' | ||
26 | 28 | ||
27 | @Injectable() | 29 | @Injectable() |
28 | export class VideoService { | 30 | export class VideoService { |
@@ -115,6 +117,22 @@ export class VideoService { | |||
115 | .catch((res) => this.restExtractor.handleError(res)) | 117 | .catch((res) => this.restExtractor.handleError(res)) |
116 | } | 118 | } |
117 | 119 | ||
120 | getVideoChannelVideos ( | ||
121 | videoChannel: VideoChannel, | ||
122 | videoPagination: ComponentPagination, | ||
123 | sort: VideoSortField | ||
124 | ): Observable<{ videos: Video[], totalVideos: number}> { | ||
125 | const pagination = this.restService.componentPaginationToRestPagination(videoPagination) | ||
126 | |||
127 | let params = new HttpParams() | ||
128 | params = this.restService.addRestGetParams(params, pagination, sort) | ||
129 | |||
130 | return this.authHttp | ||
131 | .get(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid + '/videos', { params }) | ||
132 | .map(this.extractVideos) | ||
133 | .catch((res) => this.restExtractor.handleError(res)) | ||
134 | } | ||
135 | |||
118 | getVideos ( | 136 | getVideos ( |
119 | videoPagination: ComponentPagination, | 137 | videoPagination: ComponentPagination, |
120 | sort: VideoSortField, | 138 | sort: VideoSortField, |
@@ -175,6 +193,13 @@ export class VideoService { | |||
175 | return this.buildBaseFeedUrls(params) | 193 | return this.buildBaseFeedUrls(params) |
176 | } | 194 | } |
177 | 195 | ||
196 | getVideoChannelFeedUrls (videoChannelId: number) { | ||
197 | let params = this.restService.addRestGetParams(new HttpParams()) | ||
198 | params = params.set('videoChannelId', videoChannelId.toString()) | ||
199 | |||
200 | return this.buildBaseFeedUrls(params) | ||
201 | } | ||
202 | |||
178 | searchVideos ( | 203 | searchVideos ( |
179 | search: string, | 204 | search: string, |
180 | videoPagination: ComponentPagination, | 205 | videoPagination: ComponentPagination, |
diff --git a/client/src/app/videos/+video-watch/video-watch.component.html b/client/src/app/videos/+video-watch/video-watch.component.html index 5d3361561..f38e90927 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html | |||
@@ -22,7 +22,7 @@ | |||
22 | </div> | 22 | </div> |
23 | 23 | ||
24 | <div class="video-info-by"> | 24 | <div class="video-info-by"> |
25 | <a [routerLink]="[ '/account', video.account.id ]" title="Go the account page"> | 25 | <a [routerLink]="[ '/accounts', video.account.id ]" title="Go the account page"> |
26 | <span>By {{ video.by }}</span> | 26 | <span>By {{ video.by }}</span> |
27 | <img [src]="video.accountAvatarUrl" alt="Account avatar" /> | 27 | <img [src]="video.accountAvatarUrl" alt="Account avatar" /> |
28 | </a> | 28 | </a> |
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss index cbf9b566a..c43bd9803 100644 --- a/client/src/sass/include/_mixins.scss +++ b/client/src/sass/include/_mixins.scss | |||
@@ -320,4 +320,48 @@ | |||
320 | color: $orange-color; | 320 | color: $orange-color; |
321 | font-weight: $font-bold; | 321 | font-weight: $font-bold; |
322 | font-size: 13px; | 322 | font-size: 13px; |
323 | } | ||
324 | |||
325 | @mixin sub-menu-with-actor { | ||
326 | height: 160px; | ||
327 | display: flex; | ||
328 | flex-direction: column; | ||
329 | align-items: start; | ||
330 | |||
331 | .actor { | ||
332 | display: flex; | ||
333 | margin-top: 20px; | ||
334 | margin-bottom: 20px; | ||
335 | |||
336 | img { | ||
337 | @include avatar(80px); | ||
338 | |||
339 | margin-right: 20px; | ||
340 | } | ||
341 | |||
342 | .actor-info { | ||
343 | display: flex; | ||
344 | flex-direction: column; | ||
345 | justify-content: center; | ||
346 | |||
347 | .actor-display-name { | ||
348 | font-size: 23px; | ||
349 | font-weight: $font-bold; | ||
350 | } | ||
351 | |||
352 | .actor-followers { | ||
353 | font-size: 15px; | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | |||
358 | .links { | ||
359 | margin-top: 0; | ||
360 | margin-bottom: 10px; | ||
361 | |||
362 | a { | ||
363 | margin-top: 0; | ||
364 | margin-bottom: 0; | ||
365 | } | ||
366 | } | ||
323 | } \ No newline at end of file | 367 | } \ No newline at end of file |
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts index 850ad12e0..499a4fc94 100644 --- a/server/tests/api/check-params/videos.ts +++ b/server/tests/api/check-params/videos.ts | |||
@@ -140,7 +140,7 @@ describe('Test videos API validator', function () { | |||
140 | let path: string | 140 | let path: string |
141 | 141 | ||
142 | before(async function () { | 142 | before(async function () { |
143 | path = '/api/v1/accounts/' + accountUUID + '/video-channels/' + channelUUID + '/videos' | 143 | path = '/api/v1/video-channels/' + channelUUID + '/videos' |
144 | }) | 144 | }) |
145 | 145 | ||
146 | it('Should fail with a bad start pagination', async function () { | 146 | it('Should fail with a bad start pagination', async function () { |
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts index 6238cdc08..e462a2d47 100644 --- a/server/tests/api/videos/multiple-servers.ts +++ b/server/tests/api/videos/multiple-servers.ts | |||
@@ -47,7 +47,6 @@ describe('Test multiple servers', function () { | |||
47 | let servers: ServerInfo[] = [] | 47 | let servers: ServerInfo[] = [] |
48 | const toRemove = [] | 48 | const toRemove = [] |
49 | let videoUUID = '' | 49 | let videoUUID = '' |
50 | let accountId: number | ||
51 | let videoChannelId: number | 50 | let videoChannelId: number |
52 | 51 | ||
53 | before(async function () { | 52 | before(async function () { |
@@ -59,16 +58,11 @@ describe('Test multiple servers', function () { | |||
59 | await setAccessTokensToServers(servers) | 58 | await setAccessTokensToServers(servers) |
60 | 59 | ||
61 | { | 60 | { |
62 | const res = await getAccountsList(servers[0].url) | ||
63 | accountId = res.body.data[0].id | ||
64 | } | ||
65 | |||
66 | { | ||
67 | const videoChannel = { | 61 | const videoChannel = { |
68 | name: 'my channel', | 62 | name: 'my channel', |
69 | description: 'super channel' | 63 | description: 'super channel' |
70 | } | 64 | } |
71 | await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, accountId, videoChannel) | 65 | await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel) |
72 | const channelRes = await getVideoChannelsList(servers[ 0 ].url, 0, 1) | 66 | const channelRes = await getVideoChannelsList(servers[ 0 ].url, 0, 1) |
73 | videoChannelId = channelRes.body.data[ 0 ].id | 67 | videoChannelId = channelRes.body.data[ 0 ].id |
74 | } | 68 | } |