Add ability to embed a video in Twitter
The instance should be whitelisted first
This commit is contained in:
parent
c7b0dacb28
commit
8be1afa12b
14 changed files with 355 additions and 213 deletions
|
@ -1,222 +1,259 @@
|
|||
<div class="form-sub-title">Update PeerTube configuration</div>
|
||||
|
||||
<form role="form" [formGroup]="form">
|
||||
|
||||
<div class="inner-form-title">Instance</div>
|
||||
<tabset class="root-tabset bootstrap">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="instanceName">Name</label>
|
||||
<input
|
||||
type="text" id="instanceName"
|
||||
formControlName="instanceName" [ngClass]="{ 'input-error': formErrors['instanceName'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.instanceName" class="form-error">
|
||||
{{ formErrors.instanceName }}
|
||||
</div>
|
||||
</div>
|
||||
<tab heading="Basic configuration">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="instanceShortDescription">Short description</label>
|
||||
<textarea
|
||||
id="instanceShortDescription" formControlName="instanceShortDescription"
|
||||
[ngClass]="{ 'input-error': formErrors['instanceShortDescription'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.instanceShortDescription" class="form-error">
|
||||
{{ formErrors.instanceShortDescription }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="inner-form-title">Instance</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="instanceDescription">Description</label><my-help helpType="markdownText"></my-help>
|
||||
<my-markdown-textarea
|
||||
id="instanceDescription" formControlName="instanceDescription" textareaWidth="500px" [previewColumn]="true"
|
||||
[classes]="{ 'input-error': formErrors['instanceDescription'] }"
|
||||
></my-markdown-textarea>
|
||||
<div *ngIf="formErrors.instanceDescription" class="form-error">
|
||||
{{ formErrors.instanceDescription }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="instanceTerms">Terms</label><my-help helpType="markdownText"></my-help>
|
||||
<my-markdown-textarea
|
||||
id="instanceTerms" formControlName="instanceTerms" textareaWidth="500px" [previewColumn]="true"
|
||||
[ngClass]="{ 'input-error': formErrors['instanceTerms'] }"
|
||||
></my-markdown-textarea>
|
||||
<div *ngIf="formErrors.instanceTerms" class="form-error">
|
||||
{{ formErrors.instanceTerms }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="instanceDefaultClientRoute">Default client route</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="instanceDefaultClientRoute" formControlName="instanceDefaultClientRoute">
|
||||
<option value="/videos/trending">Videos Trending</option>
|
||||
<option value="/videos/recently-added">Videos Recently Added</option>
|
||||
<option value="/videos/local">Local videos</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.instanceDefaultClientRoute" class="form-error">
|
||||
{{ formErrors.instanceDefaultClientRoute }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="instanceDefaultNSFWPolicy">Policy on videos containing sensitive content</label>
|
||||
<my-help helpType="custom" customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."></my-help>
|
||||
|
||||
<div class="peertube-select-container">
|
||||
<select id="instanceDefaultNSFWPolicy" formControlName="instanceDefaultNSFWPolicy">
|
||||
<option value="do_not_list">Do not list</option>
|
||||
<option value="blur">Blur thumbnails</option>
|
||||
<option value="display">Display</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.instanceDefaultNSFWPolicy" class="form-error">
|
||||
{{ formErrors.instanceDefaultNSFWPolicy }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner-form-title">Cache</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="cachePreviewsSize">Preview cache size</label>
|
||||
<input
|
||||
type="text" id="cachePreviewsSize"
|
||||
formControlName="cachePreviewsSize" [ngClass]="{ 'input-error': formErrors['cachePreviewsSize'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.cachePreviewsSize" class="form-error">
|
||||
{{ formErrors.cachePreviewsSize }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner-form-title">Signup</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="signupEnabled" formControlName="signupEnabled">
|
||||
|
||||
<label for="signupEnabled"></label>
|
||||
<label for="signupEnabled">Signup enabled</label>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isSignupEnabled()" class="form-group">
|
||||
<label for="signupLimit">Signup limit</label>
|
||||
<input
|
||||
type="text" id="signupLimit"
|
||||
formControlName="signupLimit" [ngClass]="{ 'input-error': formErrors['signupLimit'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.signupLimit" class="form-error">
|
||||
{{ formErrors.signupLimit }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner-form-title">Administrator</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="adminEmail">Admin email</label>
|
||||
<input
|
||||
type="text" id="adminEmail"
|
||||
formControlName="adminEmail" [ngClass]="{ 'input-error': formErrors['adminEmail'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.adminEmail" class="form-error">
|
||||
{{ formErrors.adminEmail }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner-form-title">Users</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="userVideoQuota">User default video quota</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="userVideoQuota" formControlName="userVideoQuota">
|
||||
<option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value">
|
||||
{{ videoQuotaOption.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.userVideoQuota" class="form-error">
|
||||
{{ formErrors.userVideoQuota }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner-form-title">Transcoding</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="transcodingEnabled" formControlName="transcodingEnabled">
|
||||
|
||||
<label for="transcodingEnabled"></label>
|
||||
<label for="transcodingEnabled">Transcoding enabled</label>
|
||||
</div>
|
||||
|
||||
<ng-template [ngIf]="isTranscodingEnabled()">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="transcodingThreads">Transcoding threads</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="transcodingThreads" formControlName="transcodingThreads">
|
||||
<option *ngFor="let transcodingThreadOption of transcodingThreadOptions" [value]="transcodingThreadOption.value">
|
||||
{{ transcodingThreadOption.label }}
|
||||
</option>
|
||||
</select>
|
||||
<div class="form-group">
|
||||
<label for="instanceName">Name</label>
|
||||
<input
|
||||
type="text" id="instanceName"
|
||||
formControlName="instanceName" [ngClass]="{ 'input-error': formErrors['instanceName'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.instanceName" class="form-error">
|
||||
{{ formErrors.instanceName }}
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="formErrors.transcodingThreads" class="form-error">
|
||||
{{ formErrors.transcodingThreads }}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="instanceShortDescription">Short description</label>
|
||||
<textarea
|
||||
id="instanceShortDescription" formControlName="instanceShortDescription"
|
||||
[ngClass]="{ 'input-error': formErrors['instanceShortDescription'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.instanceShortDescription" class="form-error">
|
||||
{{ formErrors.instanceShortDescription }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" *ngFor="let resolution of resolutions">
|
||||
<input
|
||||
type="checkbox" [id]="getResolutionKey(resolution)"
|
||||
[formControlName]="getResolutionKey(resolution)"
|
||||
>
|
||||
<label [for]="getResolutionKey(resolution)"></label>
|
||||
<label [for]="getResolutionKey(resolution)">Resolution {{ resolution }} enabled</label>
|
||||
</div>
|
||||
</ng-template>
|
||||
<div class="form-group">
|
||||
<label for="instanceDescription">Description</label><my-help helpType="markdownText"></my-help>
|
||||
<my-markdown-textarea
|
||||
id="instanceDescription" formControlName="instanceDescription" textareaWidth="500px" [previewColumn]="true"
|
||||
[classes]="{ 'input-error': formErrors['instanceDescription'] }"
|
||||
></my-markdown-textarea>
|
||||
<div *ngIf="formErrors.instanceDescription" class="form-error">
|
||||
{{ formErrors.instanceDescription }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner-form-title">Customizations</div>
|
||||
<div class="form-group">
|
||||
<label for="instanceTerms">Terms</label><my-help helpType="markdownText"></my-help>
|
||||
<my-markdown-textarea
|
||||
id="instanceTerms" formControlName="instanceTerms" textareaWidth="500px" [previewColumn]="true"
|
||||
[ngClass]="{ 'input-error': formErrors['instanceTerms'] }"
|
||||
></my-markdown-textarea>
|
||||
<div *ngIf="formErrors.instanceTerms" class="form-error">
|
||||
{{ formErrors.instanceTerms }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="customizationJavascript">JavaScript</label>
|
||||
<my-help helpType="custom" customHtml="Write directly JavaScript code.<br />Example: <pre>console.log('my instance is amazing');</pre>"></my-help>
|
||||
<textarea
|
||||
id="customizationJavascript" formControlName="customizationJavascript"
|
||||
[ngClass]="{ 'input-error': formErrors['customizationJavascript'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.customizationJavascript" class="form-error">
|
||||
{{ formErrors.customizationJavascript }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="instanceDefaultClientRoute">Default client route</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="instanceDefaultClientRoute" formControlName="instanceDefaultClientRoute">
|
||||
<option value="/videos/trending">Videos Trending</option>
|
||||
<option value="/videos/recently-added">Videos Recently Added</option>
|
||||
<option value="/videos/local">Local videos</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.instanceDefaultClientRoute" class="form-error">
|
||||
{{ formErrors.instanceDefaultClientRoute }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="customizationCSS">CSS</label>
|
||||
<my-help
|
||||
helpType="custom"
|
||||
customHtml="
|
||||
Write directly CSS code. Example:<br />
|
||||
<pre>
|
||||
body {
|
||||
background-color: red;
|
||||
}
|
||||
</pre>
|
||||
<div class="form-group">
|
||||
<label for="instanceDefaultNSFWPolicy">Policy on videos containing sensitive content</label>
|
||||
<my-help helpType="custom" customHtml="With <strong>Do not list</strong> or <strong>Blur thumbnails</strong>, a confirmation will be requested to watch the video."></my-help>
|
||||
|
||||
Prepend with <em>#custom-css</em> to override styles. Example:
|
||||
<pre>
|
||||
#custom-css .logged-in-email {
|
||||
color: red;
|
||||
}
|
||||
</pre>
|
||||
"
|
||||
></my-help>
|
||||
<textarea
|
||||
id="customizationCSS" formControlName="customizationCSS"
|
||||
[ngClass]="{ 'input-error': formErrors['customizationCSS'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.customizationCSS" class="form-error">
|
||||
{{ formErrors.customizationCSS }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="peertube-select-container">
|
||||
<select id="instanceDefaultNSFWPolicy" formControlName="instanceDefaultNSFWPolicy">
|
||||
<option value="do_not_list">Do not list</option>
|
||||
<option value="blur">Blur thumbnails</option>
|
||||
<option value="display">Display</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.instanceDefaultNSFWPolicy" class="form-error">
|
||||
{{ formErrors.instanceDefaultNSFWPolicy }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner-form-title">Signup</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="signupEnabled" formControlName="signupEnabled">
|
||||
|
||||
<label for="signupEnabled"></label>
|
||||
<label for="signupEnabled">Signup enabled</label>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isSignupEnabled()" class="form-group">
|
||||
<label for="signupLimit">Signup limit</label>
|
||||
<input
|
||||
type="text" id="signupLimit"
|
||||
formControlName="signupLimit" [ngClass]="{ 'input-error': formErrors['signupLimit'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.signupLimit" class="form-error">
|
||||
{{ formErrors.signupLimit }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner-form-title">Administrator</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="adminEmail">Admin email</label>
|
||||
<input
|
||||
type="text" id="adminEmail"
|
||||
formControlName="adminEmail" [ngClass]="{ 'input-error': formErrors['adminEmail'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.adminEmail" class="form-error">
|
||||
{{ formErrors.adminEmail }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner-form-title">Users</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="userVideoQuota">User default video quota</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="userVideoQuota" formControlName="userVideoQuota">
|
||||
<option *ngFor="let videoQuotaOption of videoQuotaOptions" [value]="videoQuotaOption.value">
|
||||
{{ videoQuotaOption.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.userVideoQuota" class="form-error">
|
||||
{{ formErrors.userVideoQuota }}
|
||||
</div>
|
||||
</div>
|
||||
</tab>
|
||||
|
||||
<tab heading="Services">
|
||||
|
||||
<div class="inner-form-title">Twitter</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="signupLimit">Your Twitter username</label>
|
||||
<my-help helpType="custom" customHtml="The Twitter @username the cards (created by PeerTube video shares) should be attributed to."></my-help>
|
||||
<input
|
||||
type="text" id="servicesTwitterUsername"
|
||||
formControlName="servicesTwitterUsername" [ngClass]="{ 'input-error': formErrors['servicesTwitterUsername'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.servicesTwitterUsername" class="form-error">
|
||||
{{ formErrors.servicesTwitterUsername }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="servicesTwitterWhitelisted" formControlName="servicesTwitterWhitelisted">
|
||||
|
||||
<label for="servicesTwitterWhitelisted"></label>
|
||||
<label for="servicesTwitterWhitelisted">Instance whitelisted by Twitter</label>
|
||||
<my-help helpType="custom" customHtml="If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
|
||||
If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br />
|
||||
Check this checkbox, save the configuration and test on <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a> to see if you instance is whitelisted."></my-help>
|
||||
|
||||
</div>
|
||||
</tab>
|
||||
|
||||
<tab heading="Advanced configuration">
|
||||
|
||||
<div class="inner-form-title">Transcoding</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="checkbox" id="transcodingEnabled" formControlName="transcodingEnabled">
|
||||
|
||||
<label for="transcodingEnabled"></label>
|
||||
<label for="transcodingEnabled">Transcoding enabled</label>
|
||||
</div>
|
||||
|
||||
<ng-template [ngIf]="isTranscodingEnabled()">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="transcodingThreads">Transcoding threads</label>
|
||||
<div class="peertube-select-container">
|
||||
<select id="transcodingThreads" formControlName="transcodingThreads">
|
||||
<option *ngFor="let transcodingThreadOption of transcodingThreadOptions" [value]="transcodingThreadOption.value">
|
||||
{{ transcodingThreadOption.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div *ngIf="formErrors.transcodingThreads" class="form-error">
|
||||
{{ formErrors.transcodingThreads }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" *ngFor="let resolution of resolutions">
|
||||
<input
|
||||
type="checkbox" [id]="getResolutionKey(resolution)"
|
||||
[formControlName]="getResolutionKey(resolution)"
|
||||
>
|
||||
<label [for]="getResolutionKey(resolution)"></label>
|
||||
<label [for]="getResolutionKey(resolution)">Resolution {{ resolution }} enabled</label>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<div class="inner-form-title">Cache</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="cachePreviewsSize">Preview cache size</label>
|
||||
<my-help helpType="custom" customHtml="Previews are not federated. We fetch them directly from the origin instance and cache them."></my-help>
|
||||
|
||||
<input
|
||||
type="text" id="cachePreviewsSize"
|
||||
formControlName="cachePreviewsSize" [ngClass]="{ 'input-error': formErrors['cachePreviewsSize'] }"
|
||||
>
|
||||
<div *ngIf="formErrors.cachePreviewsSize" class="form-error">
|
||||
{{ formErrors.cachePreviewsSize }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inner-form-title">Customizations</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="customizationJavascript">JavaScript</label>
|
||||
<my-help helpType="custom" customHtml="Write directly JavaScript code.<br />Example: <pre>console.log('my instance is amazing');</pre>"></my-help>
|
||||
<textarea
|
||||
id="customizationJavascript" formControlName="customizationJavascript"
|
||||
[ngClass]="{ 'input-error': formErrors['customizationJavascript'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.customizationJavascript" class="form-error">
|
||||
{{ formErrors.customizationJavascript }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="customizationCSS">CSS</label>
|
||||
<my-help
|
||||
helpType="custom"
|
||||
customHtml="
|
||||
Write directly CSS code. Example:<br />
|
||||
<pre>
|
||||
body {
|
||||
background-color: red;
|
||||
}
|
||||
</pre>
|
||||
|
||||
Prepend with <em>#custom-css</em> to override styles. Example:
|
||||
<pre>
|
||||
#custom-css .logged-in-email {
|
||||
color: red;
|
||||
}
|
||||
</pre>
|
||||
"
|
||||
></my-help>
|
||||
<textarea
|
||||
id="customizationCSS" formControlName="customizationCSS"
|
||||
[ngClass]="{ 'input-error': formErrors['customizationCSS'] }"
|
||||
></textarea>
|
||||
<div *ngIf="formErrors.customizationCSS" class="form-error">
|
||||
{{ formErrors.customizationCSS }}
|
||||
</div>
|
||||
</div>
|
||||
</tab>
|
||||
</tabset>
|
||||
|
||||
<input (click)="formValidated()" type="submit" value="Update configuration" [disabled]="!form.valid">
|
||||
</form>
|
||||
|
|
|
@ -8,7 +8,7 @@ import { FormReactive, USER_VIDEO_QUOTA } from '@app/shared'
|
|||
import {
|
||||
ADMIN_EMAIL,
|
||||
CACHE_PREVIEWS_SIZE,
|
||||
INSTANCE_NAME, INSTANCE_SHORT_DESCRIPTION,
|
||||
INSTANCE_NAME, INSTANCE_SHORT_DESCRIPTION, SERVICES_TWITTER_USERNAME,
|
||||
SIGNUP_LIMIT,
|
||||
TRANSCODING_THREADS
|
||||
} from '@app/shared/forms/form-validators/custom-config'
|
||||
|
@ -49,6 +49,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
|
|||
instanceTerms: '',
|
||||
instanceDefaultClientRoute: '',
|
||||
instanceDefaultNSFWPolicy: '',
|
||||
servicesTwitterUsername: '',
|
||||
cachePreviewsSize: '',
|
||||
signupLimit: '',
|
||||
adminEmail: '',
|
||||
|
@ -60,6 +61,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
|
|||
validationMessages = {
|
||||
instanceShortDescription: INSTANCE_SHORT_DESCRIPTION.MESSAGES,
|
||||
instanceName: INSTANCE_NAME.MESSAGES,
|
||||
servicesTwitterUsername: SERVICES_TWITTER_USERNAME,
|
||||
cachePreviewsSize: CACHE_PREVIEWS_SIZE.MESSAGES,
|
||||
signupLimit: SIGNUP_LIMIT.MESSAGES,
|
||||
adminEmail: ADMIN_EMAIL.MESSAGES,
|
||||
|
@ -92,6 +94,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
|
|||
instanceTerms: [ '' ],
|
||||
instanceDefaultClientRoute: [ '' ],
|
||||
instanceDefaultNSFWPolicy: [ '' ],
|
||||
servicesTwitterUsername: [ '', SERVICES_TWITTER_USERNAME.VALIDATORS ],
|
||||
servicesTwitterWhitelisted: [ ],
|
||||
cachePreviewsSize: [ '', CACHE_PREVIEWS_SIZE.VALIDATORS ],
|
||||
signupEnabled: [ ],
|
||||
signupLimit: [ '', SIGNUP_LIMIT.VALIDATORS ],
|
||||
|
@ -175,6 +179,12 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
|
|||
css: this.form.value['customizationCSS']
|
||||
}
|
||||
},
|
||||
services: {
|
||||
twitter: {
|
||||
username: this.form.value['servicesTwitterUsername'],
|
||||
whitelisted: this.form.value['servicesTwitterWhitelisted']
|
||||
}
|
||||
},
|
||||
cache: {
|
||||
previews: {
|
||||
size: this.form.value['cachePreviewsSize']
|
||||
|
@ -228,6 +238,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
|
|||
instanceTerms: this.customConfig.instance.terms,
|
||||
instanceDefaultClientRoute: this.customConfig.instance.defaultClientRoute,
|
||||
instanceDefaultNSFWPolicy: this.customConfig.instance.defaultNSFWPolicy,
|
||||
servicesTwitterUsername: this.customConfig.services.twitter.username,
|
||||
servicesTwitterWhitelisted: this.customConfig.services.twitter.whitelisted,
|
||||
cachePreviewsSize: this.customConfig.cache.previews.size,
|
||||
signupEnabled: this.customConfig.signup.enabled,
|
||||
signupLimit: this.customConfig.signup.limit,
|
||||
|
|
|
@ -14,6 +14,13 @@ export const INSTANCE_SHORT_DESCRIPTION = {
|
|||
}
|
||||
}
|
||||
|
||||
export const SERVICES_TWITTER_USERNAME = {
|
||||
VALIDATORS: [ Validators.required ],
|
||||
MESSAGES: {
|
||||
'required': 'Twitter username is required.'
|
||||
}
|
||||
}
|
||||
|
||||
export const CACHE_PREVIEWS_SIZE = {
|
||||
VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ],
|
||||
MESSAGES: {
|
||||
|
|
|
@ -35,6 +35,7 @@ import 'core-js/es6/regexp';
|
|||
import 'core-js/es6/map';
|
||||
import 'core-js/es6/weak-map';
|
||||
import 'core-js/es6/set';
|
||||
import 'core-js/es7/object';
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
@ -44,7 +45,6 @@ import 'core-js/es6/set';
|
|||
// For Google Bot
|
||||
import 'core-js/es6/reflect';
|
||||
|
||||
|
||||
/** Evergreen browsers require these. **/
|
||||
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
|
||||
import 'core-js/es7/reflect'
|
||||
|
|
|
@ -90,3 +90,12 @@ instance:
|
|||
customizations:
|
||||
javascript: '' # Directly your JavaScript code (without <script> tags). Will be eval at runtime
|
||||
css: '' # Directly your CSS code (without <style> tags). Will be injected at runtime
|
||||
|
||||
services:
|
||||
# Cards configuration to format video in Twitter
|
||||
twitter:
|
||||
username: '@Chocobozzz' # The Twitter @username the card should be attributed to
|
||||
# If true, a video player will be embedded in the Twitter feed on PeerTube video share
|
||||
# If false, we use an image link card that will redirect on your PeerTube instance
|
||||
# Change it to "true", and then test on https://cards-dev.twitter.com/validator to see if you are whitelisted
|
||||
whitelisted: false
|
||||
|
|
|
@ -106,3 +106,12 @@ instance:
|
|||
customizations:
|
||||
javascript: '' # Directly your JavaScript code (without <script> tags). Will be eval at runtime
|
||||
css: '' # Directly your CSS code (without <style> tags). Will be injected at runtime
|
||||
|
||||
services:
|
||||
# Cards configuration to format video in Twitter
|
||||
twitter:
|
||||
username: '@Chocobozzz' # The Twitter @username the card should be attributed to
|
||||
# If true, a video player will be embedded in the Twitter feed on PeerTube video share
|
||||
# If false, we use an image link card that will redirect on your PeerTube instance
|
||||
# Test on https://cards-dev.twitter.com/validator to see if you are whitelisted
|
||||
whitelisted: false
|
|
@ -161,6 +161,12 @@ function customConfig (): CustomConfig {
|
|||
javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT
|
||||
}
|
||||
},
|
||||
services: {
|
||||
twitter: {
|
||||
username: CONFIG.SERVICES.TWITTER.USERNAME,
|
||||
whitelisted: CONFIG.SERVICES.TWITTER.WHITELISTED
|
||||
}
|
||||
},
|
||||
cache: {
|
||||
previews: {
|
||||
size: CONFIG.CACHE.PREVIEWS.SIZE
|
||||
|
|
|
@ -77,8 +77,8 @@ function addOpenGraphAndOEmbedTags (htmlStringPage: string, video: VideoModel) {
|
|||
'description': videoDescriptionEscaped,
|
||||
'image': previewUrl,
|
||||
|
||||
'twitter:card': 'summary_large_image',
|
||||
'twitter:site': '@Chocobozzz',
|
||||
'twitter:card': CONFIG.SERVICES.TWITTER.WHITELISTED ? 'player' : 'summary_large_image',
|
||||
'twitter:site': CONFIG.SERVICES.TWITTER.USERNAME,
|
||||
'twitter:title': videoNameEscaped,
|
||||
'twitter:description': videoDescriptionEscaped,
|
||||
'twitter:image': previewUrl,
|
||||
|
|
|
@ -29,7 +29,8 @@ function checkMissedConfig () {
|
|||
'user.video_quota',
|
||||
'cache.previews.size', 'admin.email', 'signup.enabled', 'signup.limit', 'transcoding.enabled', 'transcoding.threads',
|
||||
'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route',
|
||||
'instance.default_nsfw_policy'
|
||||
'instance.default_nsfw_policy',
|
||||
'services.twitter.username', 'services.twitter.whitelisted'
|
||||
]
|
||||
const miss: string[] = []
|
||||
|
||||
|
|
|
@ -174,6 +174,12 @@ const CONFIG = {
|
|||
get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') },
|
||||
get CSS () { return config.get<string>('instance.customizations.css') }
|
||||
}
|
||||
},
|
||||
SERVICES: {
|
||||
TWITTER: {
|
||||
get USERNAME () { return config.get<string>('services.twitter.username') },
|
||||
get WHITELISTED () { return config.get<boolean>('services.twitter.whitelisted') }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,12 @@ describe('Test config API validators', function () {
|
|||
css: 'body { background-color: red; }'
|
||||
}
|
||||
},
|
||||
services: {
|
||||
twitter: {
|
||||
username: '@MySuperUsername',
|
||||
whitelisted: true
|
||||
}
|
||||
},
|
||||
cache: {
|
||||
previews: {
|
||||
size: 2
|
||||
|
|
|
@ -62,6 +62,8 @@ describe('Test config', function () {
|
|||
expect(data.instance.defaultNSFWPolicy).to.equal('display')
|
||||
expect(data.instance.customizations.css).to.be.empty
|
||||
expect(data.instance.customizations.javascript).to.be.empty
|
||||
expect(data.services.twitter.username).to.equal('@Chocobozzz')
|
||||
expect(data.services.twitter.whitelisted).to.be.false
|
||||
expect(data.cache.previews.size).to.equal(1)
|
||||
expect(data.signup.enabled).to.be.true
|
||||
expect(data.signup.limit).to.equal(4)
|
||||
|
@ -90,6 +92,12 @@ describe('Test config', function () {
|
|||
css: 'body { background-color: red; }'
|
||||
}
|
||||
},
|
||||
services: {
|
||||
twitter: {
|
||||
username: '@Kuja',
|
||||
whitelisted: true
|
||||
}
|
||||
},
|
||||
cache: {
|
||||
previews: {
|
||||
size: 2
|
||||
|
@ -130,6 +138,8 @@ describe('Test config', function () {
|
|||
expect(data.instance.defaultNSFWPolicy).to.equal('blur')
|
||||
expect(data.instance.customizations.javascript).to.equal('alert("coucou")')
|
||||
expect(data.instance.customizations.css).to.equal('body { background-color: red; }')
|
||||
expect(data.services.twitter.username).to.equal('@Kuja')
|
||||
expect(data.services.twitter.whitelisted).to.be.true
|
||||
expect(data.cache.previews.size).to.equal(2)
|
||||
expect(data.signup.enabled).to.be.false
|
||||
expect(data.signup.limit).to.equal(5)
|
||||
|
@ -162,6 +172,8 @@ describe('Test config', function () {
|
|||
expect(data.instance.defaultNSFWPolicy).to.equal('blur')
|
||||
expect(data.instance.customizations.javascript).to.equal('alert("coucou")')
|
||||
expect(data.instance.customizations.css).to.equal('body { background-color: red; }')
|
||||
expect(data.services.twitter.username).to.equal('@Kuja')
|
||||
expect(data.services.twitter.whitelisted).to.be.true
|
||||
expect(data.cache.previews.size).to.equal(2)
|
||||
expect(data.signup.enabled).to.be.false
|
||||
expect(data.signup.limit).to.equal(5)
|
||||
|
@ -205,6 +217,8 @@ describe('Test config', function () {
|
|||
expect(data.instance.defaultNSFWPolicy).to.equal('display')
|
||||
expect(data.instance.customizations.css).to.be.empty
|
||||
expect(data.instance.customizations.javascript).to.be.empty
|
||||
expect(data.services.twitter.username).to.equal('@Chocobozzz')
|
||||
expect(data.services.twitter.whitelisted).to.be.false
|
||||
expect(data.cache.previews.size).to.equal(1)
|
||||
expect(data.signup.enabled).to.be.true
|
||||
expect(data.signup.limit).to.equal(4)
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
runServer,
|
||||
serverLogin,
|
||||
uploadVideo,
|
||||
getVideosList
|
||||
getVideosList, updateCustomConfig, getCustomConfig
|
||||
} from './utils'
|
||||
|
||||
describe('Test a client controllers', function () {
|
||||
|
@ -73,6 +73,34 @@ describe('Test a client controllers', function () {
|
|||
expect(res.text).to.contain(expectedLink)
|
||||
})
|
||||
|
||||
it('Should have valid twitter card', async function () {
|
||||
const res = await request(server.url)
|
||||
.get('/videos/watch/' + server.video.uuid)
|
||||
.set('Accept', 'text/html')
|
||||
.expect(200)
|
||||
|
||||
expect(res.text).to.contain('<meta property="twitter:card" content="summary_large_image" />')
|
||||
expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />')
|
||||
})
|
||||
|
||||
it('Should have valid twitter card if Twitter is whitelisted', async function () {
|
||||
const res1 = await getCustomConfig(server.url, server.accessToken)
|
||||
const config = res1.body
|
||||
config.services.twitter = {
|
||||
username: '@Kuja',
|
||||
whitelisted: true
|
||||
}
|
||||
await updateCustomConfig(server.url, server.accessToken, config)
|
||||
|
||||
const res = await request(server.url)
|
||||
.get('/videos/watch/' + server.video.uuid)
|
||||
.set('Accept', 'text/html')
|
||||
.expect(200)
|
||||
|
||||
expect(res.text).to.contain('<meta property="twitter:card" content="player" />')
|
||||
expect(res.text).to.contain('<meta property="twitter:site" content="@Kuja" />')
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
process.kill(-server.app.pid)
|
||||
|
||||
|
|
|
@ -14,6 +14,13 @@ export interface CustomConfig {
|
|||
}
|
||||
}
|
||||
|
||||
services: {
|
||||
twitter: {
|
||||
username: string
|
||||
whitelisted: boolean
|
||||
}
|
||||
}
|
||||
|
||||
cache: {
|
||||
previews: {
|
||||
size: number
|
||||
|
|
Loading…
Reference in a new issue