Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add variant of the "hot" trending algorithm #3625

Merged
merged 5 commits into from
Jan 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@
* `language` by Aaron Jin (CC-BY)
* `video-language` by Rigel Kent (CC-BY)
* `peertube-x` by Solen DP (CC-BY)
* `flame` by Freepik (Flaticon License)


# Contributors to our 2020 crowdfunding :heart:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Subscription } from 'rxjs'
import { first, tap } from 'rxjs/operators'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, ComponentFactoryResolver, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core'
import { immutableAssign } from '@app/helpers'
Expand All @@ -11,9 +11,7 @@ import { VideoFilter } from '@shared/models'
@Component({
selector: 'my-account-search',
templateUrl: '../../shared/shared-video-miniature/abstract-video-list.html',
styleUrls: [
'../../shared/shared-video-miniature/abstract-video-list.scss'
]
styleUrls: [ '../../shared/shared-video-miniature/abstract-video-list.scss' ]
})
export class AccountSearchComponent extends AbstractVideoList implements OnInit, OnDestroy {
titlePage: string
Expand All @@ -35,6 +33,7 @@ export class AccountSearchComponent extends AbstractVideoList implements OnInit,
protected confirmService: ConfirmService,
protected screenService: ScreenService,
protected storageService: LocalStorageService,
protected cfr: ComponentFactoryResolver,
private accountService: AccountService,
private videoService: VideoService
) {
Expand Down Expand Up @@ -99,6 +98,7 @@ export class AccountSearchComponent extends AbstractVideoList implements OnInit,
}

generateSyndicationList () {
/* disable syndication */
/* method disabled */
throw new Error('Method not implemented.')
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Subscription } from 'rxjs'
import { first, tap } from 'rxjs/operators'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, ComponentFactoryResolver, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core'
import { immutableAssign } from '@app/helpers'
Expand Down Expand Up @@ -35,7 +35,8 @@ export class AccountVideosComponent extends AbstractVideoList implements OnInit,
protected screenService: ScreenService,
protected storageService: LocalStorageService,
private accountService: AccountService,
private videoService: VideoService
private videoService: VideoService,
protected cfr: ComponentFactoryResolver
) {
super()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,15 +269,35 @@ <h1 class="sr-only" i18n>Configuration</h1>
<div class="peertube-select-container">
<select id="instanceDefaultClientRoute" formControlName="defaultClientRoute" class="form-control">
<option i18n value="/videos/overview">Discover videos</option>
<option i18n value="/videos/trending">Trending videos</option>
<option i18n value="/videos/most-liked">Most liked videos</option>
<optgroup i18n-label label="Trending pages">
<option i18n value="/videos/trending">Default trending page</option>
<option i18n value="/videos/trending?alg=hot" [disabled]="!trendingVideosAlgorithmsEnabledIncludes('hot')">Hot videos</option>
<option i18n value="/videos/trending?alg=most-viewed" [disabled]="!trendingVideosAlgorithmsEnabledIncludes('most-viewed')">Most viewed videos</option>
<option i18n value="/videos/trending?alg=most-liked" [disabled]="!trendingVideosAlgorithmsEnabledIncludes('most-liked')">Most liked videos</option>
</optgroup>
<option i18n value="/videos/recently-added">Recently added videos</option>
<option i18n value="/videos/local">Local videos</option>
</select>
</div>
<div *ngIf="formErrors.instance.defaultClientRoute" class="form-error">{{ formErrors.instance.defaultClientRoute }}</div>
</div>

<div class="form-group" formGroupName="trending">
<ng-container formGroupName="videos">
<ng-container formGroupName="algorithms">
<label i18n for="trendingVideosAlgorithmsDefault">Default trending page</label>
<div class="peertube-select-container">
<select id="trendingVideosAlgorithmsDefault" formControlName="default" class="form-control">
<option i18n value="hot">Hot videos</option>
<option i18n value="most-viewed">Most viewed videos</option>
<option i18n value="most-liked">Most liked videos</option>
</select>
</div>
<div *ngIf="formErrors.trending.videos.algorithms.default" class="form-error">{{ formErrors.trending.videos.algorithms.default }}</div>
</ng-container>
</ng-container>
</div>

</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,14 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A
}
}
},
trending: {
videos: {
algorithms: {
enabled: null,
default: null
}
}
},
admin: {
email: ADMIN_EMAIL_VALIDATOR
},
Expand Down Expand Up @@ -364,6 +372,10 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit, A
return this.form.value['followings']['instance']['autoFollowIndex']['enabled'] === true
}

trendingVideosAlgorithmsEnabledIncludes (algorithm: string) {
return this.form.value['trending']['videos']['algorithms']['enabled'].find((e: string) => e === algorithm)
}

async formValidated () {
const value: CustomConfig = this.form.getRawValue()

Expand Down
6 changes: 4 additions & 2 deletions client/src/app/+my-library/my-history/my-history.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, ComponentFactoryResolver, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import {
AuthService,
Expand Down Expand Up @@ -42,7 +42,8 @@ export class MyHistoryComponent extends AbstractVideoList implements OnInit, OnD
protected screenService: ScreenService,
protected storageService: LocalStorageService,
private confirmService: ConfirmService,
private userHistoryService: UserHistoryService
private userHistoryService: UserHistoryService,
protected cfr: ComponentFactoryResolver
) {
super()

Expand Down Expand Up @@ -95,6 +96,7 @@ export class MyHistoryComponent extends AbstractVideoList implements OnInit, OnD
}

generateSyndicationList () {
/* method disabled */
throw new Error('Method not implemented.')
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Subscription } from 'rxjs'
import { first, tap } from 'rxjs/operators'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { Component, ComponentFactoryResolver, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, ConfirmService, LocalStorageService, Notifier, ScreenService, ServerService, UserService } from '@app/core'
import { immutableAssign } from '@app/helpers'
Expand Down Expand Up @@ -34,6 +34,7 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
protected confirmService: ConfirmService,
protected screenService: ScreenService,
protected storageService: LocalStorageService,
protected cfr: ComponentFactoryResolver,
private videoChannelService: VideoChannelService,
private videoService: VideoService
) {
Expand Down
3 changes: 1 addition & 2 deletions client/src/app/+videos/video-list/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export * from './overview'
export * from './trending'
export * from './video-local.component'
export * from './video-recently-added.component'
export * from './video-trending.component'
export * from './video-most-liked.component'
2 changes: 2 additions & 0 deletions client/src/app/+videos/video-list/trending/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './video-trending-header.component'
export * from './video-trending.component'
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" [(ngModel)]="data.model" (ngModelChange)="setSort()">
<ng-container *ngFor="let button of buttons">
<label *ngIf="!button.hidden" ngbButtonLabel class="btn-light" placement="bottom" [ngbTooltip]="button.tooltip" container="body">
<my-global-icon [iconName]="button.iconName"></my-global-icon>
<input ngbButton type="radio" [value]="button.value"> {{ button.label }}
</label>
</ng-container>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.btn-group label {
border: 1px solid transparent;
border-radius: 9999px !important;
padding: 5px 16px;
opacity: .8;

&:not(:first-child) {
margin-left: .5rem;
}

my-global-icon {
position: relative;
top: -2px;
height: 1rem;
margin-right: .1rem;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Component, HostBinding, Inject, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { VideoListHeaderComponent } from '@app/shared/shared-video-miniature'
import { GlobalIconName } from '@app/shared/shared-icons'
import { ServerService } from '@app/core/server/server.service'
import { Subscription } from 'rxjs'
import { RedirectService } from '@app/core'

interface VideoTrendingHeaderItem {
label: string
iconName: GlobalIconName
value: string
tooltip?: string
hidden?: boolean
}

@Component({
selector: 'video-trending-title-page',
styleUrls: [ './video-trending-header.component.scss' ],
templateUrl: './video-trending-header.component.html'
})
export class VideoTrendingHeaderComponent extends VideoListHeaderComponent implements OnInit, OnDestroy {
@HostBinding('class') class = 'title-page title-page-single'

buttons: VideoTrendingHeaderItem[]

private algorithmChangeSub: Subscription

constructor (
@Inject('data') public data: any,
rigelk marked this conversation as resolved.
Show resolved Hide resolved
private route: ActivatedRoute,
private router: Router,
private serverService: ServerService
) {
super(data)

this.buttons = [
{
label: $localize`:A variant of Trending videos based on the number of recent interactions:Hot`,
iconName: 'flame',
value: 'hot',
tooltip: $localize`Videos totalizing the most interactions for recent videos`,
hidden: true
},
{
label: $localize`:Main variant of Trending videos based on number of recent views:Views`,
iconName: 'trending',
value: 'most-viewed',
tooltip: $localize`Videos totalizing the most views during the last 24 hours`
},
{
label: $localize`:A variant of Trending videos based on the number of likes:Likes`,
iconName: 'like',
value: 'most-liked',
tooltip: $localize`Videos that have the most likes`
}
]
}

ngOnInit () {
this.serverService.getConfig()
.subscribe(config => {
this.buttons = this.buttons.map(b => {
b.hidden = !config.trending.videos.algorithms.enabled.includes(b.value)
return b
})
})

this.algorithmChangeSub = this.route.queryParams.subscribe(
queryParams => {
const algorithm = queryParams['alg']
if (algorithm) {
this.data.model = algorithm
} else {
this.data.model = RedirectService.DEFAULT_TRENDING_ALGORITHM
}
}
)
}

ngOnDestroy () {
if (this.algorithmChangeSub) this.algorithmChangeSub.unsubscribe()
}

setSort () {
const alg = this.data.model !== RedirectService.DEFAULT_TRENDING_ALGORITHM
? this.data.model
: undefined

this.router.navigate(
[],
{
relativeTo: this.route,
queryParams: { alg },
queryParamsHandling: 'merge'
}
)
}
}
Loading