mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2024-11-14 11:04:46 +03:00
Add features table on signup
This commit is contained in:
parent
f0d4e7eb24
commit
41a676db39
@ -1,6 +1,6 @@
|
||||
<div i18n class="about-peertube-title">
|
||||
<h1 i18n class="about-peertube-title">
|
||||
About PeerTube
|
||||
</div>
|
||||
</h1>
|
||||
|
||||
<div class="description">
|
||||
<p i18n>PeerTube is a federated (ActivityPub) video streaming platform using P2P (WebTorrent) directly in the web browser.</p>
|
||||
@ -15,14 +15,14 @@
|
||||
</div>
|
||||
|
||||
<div id="p2p-privacy">
|
||||
<div i18n class="section-title">P2P & Privacy</div>
|
||||
<h3 i18n class="section-title">P2P & Privacy</h3>
|
||||
|
||||
<p i18n>
|
||||
PeerTube uses the BitTorrent protocol to share bandwidth between users.
|
||||
This implies that your IP address is stored in the instance's BitTorrent tracker as long as you download or watch the video.
|
||||
</p>
|
||||
|
||||
<h4 i18n class="p2p-privacy-title">What are the consequences?</h4>
|
||||
<h6 i18n class="p2p-privacy-title">What are the consequences?</h6>
|
||||
|
||||
<p i18n>
|
||||
In theory, someone with enough technical skills could create a script that tracks which IP is downloading which video.
|
||||
@ -64,7 +64,7 @@
|
||||
There are much more effective ways to get that kind of information.
|
||||
</p>
|
||||
|
||||
<h4 i18n class="p2p-privacy-title">How does PeerTube compare with YouTube?</h4>
|
||||
<h6 i18n class="p2p-privacy-title">How does PeerTube compare with YouTube?</h6>
|
||||
|
||||
<p i18n>
|
||||
The threats to privacy in YouTube are different from PeerTube's.
|
||||
@ -72,7 +72,7 @@
|
||||
Moreover, YouTube is owned by Google/Alphabet, a company that tracks you across many websites (via AdSense or Google Analytics).
|
||||
</p>
|
||||
|
||||
<h4 i18n class="p2p-privacy-title">What can I do to limit the exposure of my IP address?</h4>
|
||||
<h6 i18n class="p2p-privacy-title">What can I do to limit the exposure of my IP address?</h6>
|
||||
|
||||
<p i18n>
|
||||
Your IP address is public so every time you consult a website, there is a number of actors (in addition to the final website) seeing your IP in their connection logs: ISP/routers/trackers/CDN and more.
|
||||
@ -80,7 +80,7 @@
|
||||
Thinking that removing P2P from PeerTube will give you back anonymity doesn't make sense.
|
||||
</p>
|
||||
|
||||
<h4 i18n class="p2p-privacy-title">What will be done to mitigate this problem?</h4>
|
||||
<h6 i18n class="p2p-privacy-title">What will be done to mitigate this problem?</h6>
|
||||
|
||||
<p i18n>
|
||||
PeerTube is only in beta, and want to deliver the best countermeasures possible by the time the stable is released.
|
||||
|
@ -2,7 +2,7 @@
|
||||
@import '_mixins';
|
||||
|
||||
.about-peertube-title {
|
||||
font-size: 20px;
|
||||
font-size: 25px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
@ -2,8 +2,7 @@ import { Component } from '@angular/core'
|
||||
|
||||
@Component({
|
||||
selector: 'my-about',
|
||||
templateUrl: './about.component.html',
|
||||
styleUrls: [ './about.component.scss' ]
|
||||
templateUrl: './about.component.html'
|
||||
})
|
||||
|
||||
export class AboutComponent {
|
||||
|
@ -64,6 +64,14 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
|
||||
super()
|
||||
}
|
||||
|
||||
get videoQuotaOptions () {
|
||||
return EditCustomConfigComponent.videoQuotaOptions
|
||||
}
|
||||
|
||||
get videoQuotaDailyOptions () {
|
||||
return EditCustomConfigComponent.videoQuotaDailyOptions
|
||||
}
|
||||
|
||||
getResolutionKey (resolution: string) {
|
||||
return 'transcodingResolution' + resolution
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
<div class="feature-table">
|
||||
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td i18n class="label">Video quota</td>
|
||||
|
||||
<td class="value">
|
||||
<ng-container *ngIf="initialUserVideoQuota !== -1">
|
||||
{{ initialUserVideoQuota | bytes: 0 }}
|
||||
|
||||
<my-help helpType="custom" [customHtml]="quotaHelpIndication"></my-help>
|
||||
</ng-container>
|
||||
|
||||
<ng-container i18n *ngIf="initialUserVideoQuota === -1">
|
||||
Unlimited
|
||||
</ng-container>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr *ngFor="let feature of features">
|
||||
<td class="label">{{ feature.label }}</td>
|
||||
<td>
|
||||
<span *ngIf="feature.value === true" class="glyphicon glyphicon-ok"></span>
|
||||
<span *ngIf="feature.value === false" class="glyphicon glyphicon-remove"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
@ -0,0 +1,20 @@
|
||||
@import '_variables';
|
||||
@import '_mixins';
|
||||
|
||||
table {
|
||||
font-size: 14px;
|
||||
max-width: 400px;
|
||||
|
||||
.label {
|
||||
font-weight: $font-semibold;
|
||||
min-width: 330px;
|
||||
}
|
||||
|
||||
.glyphicon-ok {
|
||||
color: $green;
|
||||
}
|
||||
|
||||
.glyphicon-remove {
|
||||
color: $red;
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { ServerService } from '@app/core'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
|
||||
@Component({
|
||||
selector: 'my-instance-features-table',
|
||||
templateUrl: './instance-features-table.component.html',
|
||||
styleUrls: [ './instance-features-table.component.scss' ]
|
||||
})
|
||||
export class InstanceFeaturesTableComponent implements OnInit {
|
||||
features: { label: string, value?: boolean }[] = []
|
||||
quotaHelpIndication = ''
|
||||
|
||||
constructor (
|
||||
private i18n: I18n,
|
||||
private serverService: ServerService
|
||||
) {
|
||||
}
|
||||
|
||||
get initialUserVideoQuota () {
|
||||
return this.serverService.getConfig().user.videoQuota
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.serverService.configLoaded
|
||||
.subscribe(() => {
|
||||
this.buildFeatures()
|
||||
this.buildQuotaHelpIndication()
|
||||
})
|
||||
}
|
||||
|
||||
private buildFeatures () {
|
||||
const config = this.serverService.getConfig()
|
||||
|
||||
this.features = [
|
||||
{
|
||||
label: this.i18n('Transcode your videos in multiple resolutions'),
|
||||
value: config.transcoding.enabledResolutions.length !== 0
|
||||
},
|
||||
{
|
||||
label: this.i18n('HTTP import (YouTube, Vimeo, direct URL...)'),
|
||||
value: config.import.videos.http.enabled
|
||||
},
|
||||
{
|
||||
label: this.i18n('Torrent import'),
|
||||
value: config.import.videos.torrent.enabled
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
private getApproximateTime (seconds: number) {
|
||||
const hours = Math.floor(seconds / 3600)
|
||||
let pluralSuffix = ''
|
||||
if (hours > 1) pluralSuffix = 's'
|
||||
if (hours > 0) return `~ ${hours} hour${pluralSuffix}`
|
||||
|
||||
const minutes = Math.floor(seconds % 3600 / 60)
|
||||
|
||||
return this.i18n('~ {{minutes}} {minutes, plural, =1 {minute} other {minutes}}', { minutes })
|
||||
}
|
||||
|
||||
private buildQuotaHelpIndication () {
|
||||
if (this.initialUserVideoQuota === -1) return
|
||||
|
||||
const initialUserVideoQuotaBit = this.initialUserVideoQuota * 8
|
||||
|
||||
// 1080p: ~ 6Mbps
|
||||
// 720p: ~ 4Mbps
|
||||
// 360p: ~ 1.5Mbps
|
||||
const fullHdSeconds = initialUserVideoQuotaBit / (6 * 1000 * 1000)
|
||||
const hdSeconds = initialUserVideoQuotaBit / (4 * 1000 * 1000)
|
||||
const normalSeconds = initialUserVideoQuotaBit / (1.5 * 1000 * 1000)
|
||||
|
||||
const lines = [
|
||||
this.i18n('{{seconds}} of full HD videos', { seconds: this.getApproximateTime(fullHdSeconds) }),
|
||||
this.i18n('{{seconds}} of HD videos', { seconds: this.getApproximateTime(hdSeconds) }),
|
||||
this.i18n('{{seconds}} of average quality videos', { seconds: this.getApproximateTime(normalSeconds) })
|
||||
]
|
||||
|
||||
this.quotaHelpIndication = lines.join('<br />')
|
||||
}
|
||||
|
||||
}
|
@ -51,6 +51,7 @@ import { VideoImportService } from '@app/shared/video-import/video-import.servic
|
||||
import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component'
|
||||
import { NgbDropdownModule, NgbModalModule, NgbPopoverModule, NgbTabsetModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription'
|
||||
import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -86,7 +87,8 @@ import { SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/u
|
||||
HelpComponent,
|
||||
ReactiveFileComponent,
|
||||
PeertubeCheckboxComponent,
|
||||
SubscribeButtonComponent
|
||||
SubscribeButtonComponent,
|
||||
InstanceFeaturesTableComponent
|
||||
],
|
||||
|
||||
exports: [
|
||||
@ -119,6 +121,7 @@ import { SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/u
|
||||
ReactiveFileComponent,
|
||||
PeertubeCheckboxComponent,
|
||||
SubscribeButtonComponent,
|
||||
InstanceFeaturesTableComponent,
|
||||
|
||||
NumberFormatterPipe,
|
||||
ObjectLengthPipe,
|
||||
|
@ -4,19 +4,7 @@
|
||||
Create an account
|
||||
</div>
|
||||
|
||||
<div class="initial-user-quota">
|
||||
<span i18n class="initial-user-quota-label">Initial video quota:</span>
|
||||
|
||||
<span *ngIf="initialUserVideoQuota !== -1">
|
||||
{{ initialUserVideoQuota | bytes: 0 }}
|
||||
|
||||
<my-help helpType="custom" [customHtml]="quotaHelpIndication"></my-help>
|
||||
</span>
|
||||
|
||||
<ng-container i18n *ngIf="initialUserVideoQuota === -1">
|
||||
Unlimited
|
||||
</ng-container>
|
||||
</div>
|
||||
<my-instance-features-table></my-instance-features-table>
|
||||
|
||||
<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
|
||||
|
||||
|
@ -1,13 +1,10 @@
|
||||
@import '_variables';
|
||||
@import '_mixins';
|
||||
|
||||
.initial-user-quota {
|
||||
font-size: 15px;
|
||||
margin-bottom: 20px;
|
||||
my-instance-features-table {
|
||||
display: block;
|
||||
|
||||
.initial-user-quota-label {
|
||||
font-weight: $font-semibold;
|
||||
}
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.form-group-terms {
|
||||
@ -15,11 +12,11 @@
|
||||
}
|
||||
|
||||
.input-group {
|
||||
@include peertube-input-group(340px);
|
||||
@include peertube-input-group(400px);
|
||||
}
|
||||
|
||||
input:not([type=submit]) {
|
||||
@include peertube-input-text(340px);
|
||||
@include peertube-input-text(400px);
|
||||
display: block;
|
||||
|
||||
&#username {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { Router } from '@angular/router'
|
||||
import { ServerService } from '@app/core/server'
|
||||
import { NotificationsService } from 'angular2-notifications'
|
||||
import { UserCreate } from '../../../../shared'
|
||||
import { FormReactive, UserService, UserValidatorsService } from '../shared'
|
||||
@ -15,7 +14,6 @@ import { FormValidatorService } from '@app/shared/forms/form-validators/form-val
|
||||
})
|
||||
export class SignupComponent extends FormReactive implements OnInit {
|
||||
error: string = null
|
||||
quotaHelpIndication = ''
|
||||
|
||||
constructor (
|
||||
protected formValidatorService: FormValidatorService,
|
||||
@ -24,16 +22,11 @@ export class SignupComponent extends FormReactive implements OnInit {
|
||||
private notificationsService: NotificationsService,
|
||||
private userService: UserService,
|
||||
private redirectService: RedirectService,
|
||||
private serverService: ServerService,
|
||||
private i18n: I18n
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
get initialUserVideoQuota () {
|
||||
return this.serverService.getConfig().user.videoQuota
|
||||
}
|
||||
|
||||
get instanceHost () {
|
||||
return window.location.host
|
||||
}
|
||||
@ -45,9 +38,6 @@ export class SignupComponent extends FormReactive implements OnInit {
|
||||
email: this.userValidatorsService.USER_EMAIL,
|
||||
terms: this.userValidatorsService.USER_TERMS
|
||||
})
|
||||
|
||||
this.serverService.configLoaded
|
||||
.subscribe(() => this.buildQuotaHelpIndication())
|
||||
}
|
||||
|
||||
signup () {
|
||||
@ -67,37 +57,4 @@ export class SignupComponent extends FormReactive implements OnInit {
|
||||
err => this.error = err.message
|
||||
)
|
||||
}
|
||||
|
||||
private getApproximateTime (seconds: number) {
|
||||
const hours = Math.floor(seconds / 3600)
|
||||
let pluralSuffix = ''
|
||||
if (hours > 1) pluralSuffix = 's'
|
||||
if (hours > 0) return `~ ${hours} hour${pluralSuffix}`
|
||||
|
||||
const minutes = Math.floor(seconds % 3600 / 60)
|
||||
if (minutes > 1) pluralSuffix = 's'
|
||||
|
||||
return this.i18n('~ {{minutes}} {minutes, plural, =1 {minute} other {minutes}}', { minutes })
|
||||
}
|
||||
|
||||
private buildQuotaHelpIndication () {
|
||||
if (this.initialUserVideoQuota === -1) return
|
||||
|
||||
const initialUserVideoQuotaBit = this.initialUserVideoQuota * 8
|
||||
|
||||
// 1080p: ~ 6Mbps
|
||||
// 720p: ~ 4Mbps
|
||||
// 360p: ~ 1.5Mbps
|
||||
const fullHdSeconds = initialUserVideoQuotaBit / (6 * 1000 * 1000)
|
||||
const hdSeconds = initialUserVideoQuotaBit / (4 * 1000 * 1000)
|
||||
const normalSeconds = initialUserVideoQuotaBit / (1.5 * 1000 * 1000)
|
||||
|
||||
const lines = [
|
||||
this.i18n('{{seconds}} of full HD videos', { seconds: this.getApproximateTime(fullHdSeconds) }),
|
||||
this.i18n('{{seconds}} of HD videos', { seconds: this.getApproximateTime(hdSeconds) }),
|
||||
this.i18n('{{seconds}} of average quality videos', { seconds: this.getApproximateTime(normalSeconds) })
|
||||
]
|
||||
|
||||
this.quotaHelpIndication = lines.join('<br />')
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +226,7 @@
|
||||
}
|
||||
|
||||
&.action-button-like.activated {
|
||||
background-color: #39CC0B;
|
||||
background-color: $green;
|
||||
|
||||
.icon-like {
|
||||
background-image: url('../../../assets/images/video/like-white.svg');
|
||||
@ -234,7 +234,7 @@
|
||||
}
|
||||
|
||||
&.action-button-dislike.activated {
|
||||
background-color: #FF0000;
|
||||
background-color: $red;
|
||||
|
||||
.icon-dislike {
|
||||
background-image: url('../../../assets/images/video/dislike-white.svg');
|
||||
|
12
client/src/assets/images/global/tick.svg
Normal file
12
client/src/assets/images/global/tick.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?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(-356.000000, -115.000000)" stroke="#585858" stroke-width="2">
|
||||
<g id="8" transform="translate(356.000000, 115.000000)">
|
||||
<path d="M21,6 L9,18" id="Path-14"></path>
|
||||
<path d="M9,13 L4,18" id="Path-14" transform="translate(6.500000, 15.500000) scale(-1, 1) translate(-6.500000, -15.500000) "></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 741 B |
@ -53,12 +53,12 @@ label {
|
||||
|
||||
.form-error {
|
||||
display: block;
|
||||
color: $red-error;
|
||||
color: $red;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.input-error {
|
||||
border-color: $red-error !important;
|
||||
border-color: $red !important;
|
||||
}
|
||||
|
||||
.glyphicon-black {
|
||||
|
@ -21,7 +21,7 @@ $nav-pills-link-active-color: #000;
|
||||
//@import '~bootstrap/scss/images';
|
||||
//@import '~bootstrap/scss/code';
|
||||
@import '~bootstrap/scss/grid';
|
||||
//@import '~bootstrap/scss/tables';
|
||||
@import '~bootstrap/scss/tables';
|
||||
@import '~bootstrap/scss/forms';
|
||||
@import '~bootstrap/scss/buttons';
|
||||
//@import '~bootstrap/scss/transitions';
|
||||
|
@ -10,7 +10,9 @@ $orange-hoover-color: #F97D46;
|
||||
|
||||
$black-background: #000;
|
||||
$grey-background: #f6f2f2;
|
||||
$red-error: #FF0000;
|
||||
|
||||
$red: #FF0000;
|
||||
$green: #39CC0B;
|
||||
|
||||
$grey-actor-name: #777272;
|
||||
|
||||
|
@ -43,7 +43,7 @@ async function getConfig (req: express.Request, res: express.Response, next: exp
|
||||
const allowedForCurrentIP = isSignupAllowedForCurrentIP(req.ip)
|
||||
|
||||
const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
|
||||
.filter(key => CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
|
||||
.filter(key => CONFIG.TRANSCODING.ENABLED === CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
|
||||
.map(r => parseInt(r, 10))
|
||||
|
||||
const json: ServerConfig = {
|
||||
|
Loading…
Reference in New Issue
Block a user