Compare commits

..

No commits in common. "develop" and "master" have entirely different histories.

15 changed files with 71 additions and 131 deletions

View file

@ -1,6 +1,6 @@
<!-- If you have a question, please read FAQ.md first -->
<!-- If you report a security issue, please refrain from filling an issue, refer to SECURITY.md and follow the disclosure procedure it describes. -->
<!-- If you report a bug, please fill the following form -->
<!-- If you have a question, please read the FAQ.md first -->
<!-- If you report a security issue, please refrain from filling an issue and refer to SECURITY.md for the disclosure procedure. -->
<!-- If you report a bug, please fill the form -->
**What happened?**
@ -16,9 +16,9 @@
**Additional information**
* PeerTube version and URL:
* Browser name and version:
* PeerTube version or URL:
* Browser name/version:
* NodeJS version:
* Link to browser console log if useful:
* Link to server log if useful (`journalctl` or `/var/www/peertube/storage/logs/`):
* Link to server log if useful (journalctl or /var/www/peertube/storage/logs/):

View file

@ -196,7 +196,7 @@ Learn how to import/upload videos from CLI or admin your PeerTube instance with
See the [architecture blueprint](https://docs.joinpeertube.org/#/contribute-architecture) for a more detailed explanation of the architectural choices.
See our REST API documentation:
* OpenAPI 3.0.0 schema: [/support/doc/api/openapi.yaml](https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/api/openapi.yaml)
* OpenAPI 3.0.0 schema: [/support/doc/api/openapi.yaml](https://github.com/Chocobozzz/PeerTube/blob/support/doc/api/openapi.yaml)
* Spec explorer: [docs.joinpeertube.org/api-rest-reference.html](https://docs.joinpeertube.org/api-rest-reference.html)
See our [ActivityPub documentation](https://docs.joinpeertube.org/#/api-activitypub).

View file

@ -20,7 +20,7 @@
<ng-template pTemplate="header">
<tr>
<th style="width: 150px;">Action</th> <!-- column for action buttons -->
<th style="width: calc(100% - 300px);" i18n>Account</th>
<th style="width: 100%;" i18n>Account</th>
<th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
</tr>
</ng-template>

View file

@ -10,48 +10,45 @@
<div class="select-filter-block">
<label for="jobState" i18n>Job state</label>
<ng-select
class="select-job-state"
[(ngModel)]="jobState"
(ngModelChange)="onJobStateOrTypeChanged()"
[clearable]="false"
[searchable]="false"
>
<ng-option *ngFor="let state of jobStates" [value]="state">
<span class="badge" [ngClass]="getJobStateClass(state)">{{ state }}</span>
</ng-option>
</ng-select>
<div class="peertube-select-container">
<select id="jobState" name="jobState" [(ngModel)]="jobState" (ngModelChange)="onJobStateOrTypeChanged()" class="form-control">
<option *ngFor="let state of jobStates" [value]="state">{{ state }}</option>
</select>
</div>
</div>
</div>
<p-table
[value]="jobs" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions"
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="uniqId" [first]="pagination.start"
[tableStyle]="{'table-layout':'auto'}" (onPage)="onPage($event)"
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} jobs"
(onPage)="onPage($event)" [expandedRowKeys]="expandedRows"
[value]="jobs" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" dataKey="uniqId"
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" [first]="pagination.start"
[tableStyle]="{'table-layout':'auto'}" (onPage)="onPage($event)" [expandedRowKeys]="expandedRows"
>
<ng-template pTemplate="header">
<tr>
<th style="width: 40px"></th>
<th style="width: calc(100% - 390px)" class="job-id" i18n>ID</th>
<th style="width: 100%" class="job-id" i18n>ID</th>
<th style="width: 200px" class="job-type" i18n>Type</th>
<th style="width: 150px" class="job-date" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
<th style="width: 150px" class="job-state" i18n>State</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-expanded="expanded" let-job>
<tr>
<td class="expand-cell" [pRowToggler]="job" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body">
<span class="expander">
<td class="expand-cell">
<span class="expander" [pRowToggler]="job" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body">
<i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i>
</span>
</td>
<td class="job-id" [pRowToggler]="job" [title]="job.id">{{ job.id }}</td>
<td class="job-type" [pRowToggler]="job">{{ job.type }}</td>
<td class="job-date" [pRowToggler]="job">{{ job.createdAt | date: 'short' }}</td>
<td class="job-id" [title]="job.id">{{ job.id }}</td>
<td class="job-type">{{ job.type }}</td>
<td class="job-date">{{ job.createdAt | date: 'short' }}</td>
<td class="job-state" *ngIf="job.state === 'delayed'" class="text-muted"><span class="glyphicon glyphicon-repeat"></span> <span i18n>Delayed</span></td>
<td class="job-state" *ngIf="job.state === 'waiting'" class="text-warning"><span class="glyphicon glyphicon-hourglass"></span> <span i18n>Will start soon...</span></td>
<td class="job-state" *ngIf="job.state === 'active'" class="text-warning"><span class="glyphicon glyphicon-cog"></span> <span i18n>Running...</span></td>
<td class="job-state" *ngIf="job.state === 'completed'" class="text-success"><span class="glyphicon glyphicon-ok"></span> <span i18n>Finished</span></td>
<td class="job-state" *ngIf="job.state === 'failed'" class="text-danger"><span class="glyphicon glyphicon-remove"></span> <span i18n>Failed</span></td>
</tr>
</ng-template>
@ -77,18 +74,5 @@
</td>
</tr>
</ng-template>
<ng-template pTemplate="emptymessage">
<tr>
<td colspan="4">
<div class="no-results">
<div class="d-block">
<ng-container *ngIf="jobType === 'all'" i18n>No <span class="badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span> jobs found.</ng-container>
<ng-container *ngIf="jobType !== 'all'" i18n>No <code>{{ jobType }}</code> jobs found that are <span class="badge" [ngClass]="getJobStateClass(jobState)">{{ jobState }}</span>.</ng-container>
</div>
</div>
</td>
</tr>
</ng-template>
</p-table>

View file

@ -1,10 +1,6 @@
@import '_variables';
@import '_mixins';
.select-job-state {
min-width: 120px;
}
.job-id {
max-width: 30vw !important;
}
@ -17,6 +13,10 @@
width: 170px !important;
}
.job-state {
max-width: 60px;
}
.admin-sub-header {
flex-direction: row !important;
justify-content: flex-end;
@ -47,7 +47,3 @@ pre {
.job-error {
color: red;
}
.badge {
@include table-badge;
}

View file

@ -56,21 +56,6 @@ export class JobsComponent extends RestTable implements OnInit {
return 'JobsComponent'
}
getJobStateClass (state: JobStateClient) {
switch (state) {
case 'active':
return 'badge-blue'
case 'completed':
return 'badge-green'
case 'delayed':
return 'badge-brown'
case 'failed':
return 'badge-red'
case 'waiting':
return 'badge-yellow'
}
}
onJobStateOrTypeChanged () {
this.pagination.start = 0

View file

@ -5,30 +5,17 @@
</select>
</div>
<ng-select
[(ngModel)]="startDate"
(ngModelChange)="refresh()"
[clearable]="false"
[searchable]="false"
>
<ng-option *ngFor="let time of timeChoices" [value]="time.id">
{{ time.label }} ({{ time.id | date: time.dateFormat }} - <span i18n>now</span>)
</ng-option>
</ng-select>
<div class="peertube-select-container">
<select [(ngModel)]="startDate" (ngModelChange)="refresh()" class="form-control">
<option *ngFor="let timeChoice of timeChoices" [value]="timeChoice.id">{{ timeChoice.label }}</option>
</select>
</div>
<ng-select
[(ngModel)]="level"
(ngModelChange)="refresh()"
[clearable]="false"
[searchable]="false"
>
<ng-option *ngFor="let levelChoice of levelChoices" [value]="levelChoice.id">
<ng-container *ngIf="levelChoice.id === 'debug'"><span style="font-size:80%;color:lightgray;vertical-align:text-top;">&#11044;</span> {{ levelChoice.label }}</ng-container>
<ng-container *ngIf="levelChoice.id === 'info'"><span style="font-size:80%;color:lightskyblue;vertical-align:text-top;">&#11044;</span> {{ levelChoice.label }}</ng-container>
<ng-container *ngIf="levelChoice.id === 'warn'"><span style="font-size:80%;color:orange;vertical-align:text-top;">&#11044;</span> {{ levelChoice.label }}</ng-container>
<ng-container *ngIf="levelChoice.id === 'error'"><span style="font-size:80%;color:red;vertical-align:text-top;">&#11044;</span> {{ levelChoice.label }}</ng-container>
</ng-option>
</ng-select>
<div class="peertube-select-container" *ngIf="!isAuditLog()">
<select [(ngModel)]="level" (ngModelChange)="refresh()" class="form-control">
<option *ngFor="let levelChoice of levelChoices" [value]="levelChoice.id">{{ levelChoice.label }}</option>
</select>
</div>
<my-button i18n-label label="Refresh" icon="refresh" (click)="refresh()"></my-button>
</div>

View file

@ -52,8 +52,7 @@
}
my-button,
.peertube-select-container,
ng-select {
.peertube-select-container {
margin-left: 10px;
}
}
@ -63,7 +62,6 @@
flex-direction: column;
.peertube-select-container,
ng-select,
my-button {
width: 100% !important;
margin-left: 0px !important;
@ -82,7 +80,6 @@
flex-direction: column;
.peertube-select-container,
ng-select,
my-button {
width: 100% !important;
margin-left: 0px !important;

View file

@ -14,7 +14,7 @@ export class LogsComponent implements OnInit {
loading = false
logs: LogRow[] = []
timeChoices: { id: string, label: string, dateFormat: string }[] = []
timeChoices: { id: string, label: string }[] = []
levelChoices: { id: LogLevel, label: string }[] = []
logTypeChoices: { id: 'audit' | 'standard', label: string }[] = []
@ -76,18 +76,15 @@ export class LogsComponent implements OnInit {
this.timeChoices = [
{
id: lastWeek.toISOString(),
label: $localize`Last week`,
dateFormat: 'shortDate'
label: $localize`Last week`
},
{
id: lastDay.toISOString(),
label: $localize`Last day`,
dateFormat: 'short'
label: $localize`Last day`
},
{
id: lastHour.toISOString(),
label: $localize`Last hour`,
dateFormat: 'mediumTime'
label: $localize`Last hour`
}
]
@ -98,19 +95,19 @@ export class LogsComponent implements OnInit {
this.levelChoices = [
{
id: 'debug',
label: $localize`debug`
label: $localize`Debug`
},
{
id: 'info',
label: $localize`info`
label: $localize`Info`
},
{
id: 'warn',
label: $localize`warning`
label: $localize`Warning`
},
{
id: 'error',
label: $localize`error`
label: $localize`Error`
}
]

View file

@ -25,7 +25,7 @@
<ng-template pTemplate="header">
<tr>
<th style="width: 150px;">Action</th> <!-- column for action buttons -->
<th style="width: calc(100% - 300px);" i18n>Account</th>
<th style="width: 100%;" i18n>Account</th>
<th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
</tr>
</ng-template>

View file

@ -29,7 +29,7 @@
<ng-template pTemplate="header">
<tr>
<th style="width: 150px;">Action</th> <!-- column for action buttons -->
<th style="width: calc(100% - 300px);" i18n>Instance</th>
<th style="width: 100%;" i18n>Instance</th>
<th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
</tr>
</ng-template>

View file

@ -234,7 +234,7 @@ async function onVideoFileTranscoding (video: MVideoWithFile, videoFile: MVideoF
const fps = await getVideoFileFPS(transcodingPath)
const metadata = await getMetadataFromFile(transcodingPath)
await move(transcodingPath, outputPath, { overwrite: true })
await move(transcodingPath, outputPath)
videoFile.size = stats.size
videoFile.fps = fps
@ -242,8 +242,12 @@ async function onVideoFileTranscoding (video: MVideoWithFile, videoFile: MVideoF
await createTorrentAndSetInfoHash(video, videoFile)
await VideoFileModel.customUpsert(videoFile, 'video', undefined)
video.VideoFiles = await video.$get('VideoFiles')
const updatedVideoFile = await videoFile.save()
// Add it if this is a new created file
if (video.VideoFiles.some(f => f.id === videoFile.id) === false) {
video.VideoFiles.push(updatedVideoFile)
}
return video
}

View file

@ -1307,7 +1307,7 @@ paths:
type: string
waitTranscoding:
description: Whether or not we wait transcoding before publish the video
type: boolean
type: string
support:
description: A text tell the audience how to support the video creator
example: Please support my work on <insert crowdfunding plateform>! <3
@ -1331,9 +1331,6 @@ paths:
commentsEnabled:
description: Enable or disable comments for this video
type: boolean
downloadEnabled:
description: Enable or disable downloading for this video
type: boolean
originallyPublishedAt:
description: Date when the content was originally published
type: string
@ -1431,14 +1428,14 @@ paths:
type: string
waitTranscoding:
description: Whether or not we wait transcoding before publish the video
type: boolean
type: string
support:
description: A text tell the audience how to support the video creator
example: Please support my work on <insert crowdfunding plateform>! <3
type: string
nsfw:
description: Whether or not this video contains sensitive content
type: boolean
type: string
name:
description: Video name
type: string
@ -1453,10 +1450,7 @@ paths:
maxLength: 30
commentsEnabled:
description: Enable or disable comments for this video
type: boolean
downloadEnabled:
description: Enable or disable downloading for this video
type: boolean
type: string
scheduleUpdate:
$ref: '#/components/schemas/VideoScheduledUpdate'
required:

View file

@ -40,13 +40,13 @@ touch ./docker-volume/traefik/acme.json
```
Needs to have file mode 600:
```shell
chmod 600 ./docker-volume/traefik/acme.json
chmod 600 ./docker-volume/traefik/acme.json
```
#### Get the latest Compose file
```shell
curl https://raw.githubusercontent.com/chocobozzz/PeerTube/master/support/docker/production/docker-compose.yml > docker-compose.yml
curl https://raw.githubusercontent.com/chocobozzz/PeerTube/master/support/docker/production/docker-compose.yml > docker-compose.yml
```
View the source of the file you're about to download: [docker-compose.yml](https://github.com/Chocobozzz/PeerTube/blob/master/support/docker/production/docker-compose.yml)
@ -93,7 +93,7 @@ intuited from usage.
#### Testing local Docker setup
To test locally your Docker setup, you must add your domain (`<MY DOMAIN>`) in `/etc/hosts`:
To test locally your Docker setup, you must add your domain (`<MY DOMAIN>`) in `/etc/hosts`:
```
127.0.0.1 localhost mydomain.tld
```
@ -115,7 +115,7 @@ peertube_1 | [example.com:443] 2019-11-16 04:26:06.083 info: User password: abc
### Obtaining Your Automatically Generated DKIM DNS TXT Record
[DKIM](https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail) signature sending and RSA keys generation are enabled by the default Postfix image `mwader/postfix-relay` with [OpenDKIM](http://www.opendkim.org/).
Run `cat ./docker-volume/opendkim/keys/*/*.txt` to display your DKIM DNS TXT Record containing the public key to configure to your domain :
Run `cat ./docker-volume/opendkim/keys/*/*.txt` to display your DKIM DNS TXT Record containing the public key to configure to your domain :
```BASH
user@s:~/peertube|master⚡ ⇒ cat ./docker-volume/opendkim/keys/*/*.txt
@ -124,17 +124,13 @@ peertube._domainkey.mydomain.tld. IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
"j5joTnYwat4387VEUyGUnZ0aZxCERi+ndXv2/wMJ0tizq+a9+EgqIb+7lkUc2XciQPNuTujM25GhrQBEKznvHyPA6fHsFheymOuB763QpkmnQQLCxyLygAY9mE/5RY+5Q6J9oDOQIDAQAB" ) ; ----- DKIM key peertube for mydomain.tld
```
### Administrator password
See the production guide ["Administrator" section](https://docs.joinpeertube.org/#/install-any-os?id=administrator)
### What now?
See the production guide ["What now" section](https://docs.joinpeertube.org/#/install-any-os?id=what-now).
See the production guide ["What now" section](/support/doc/production.md#what-now).
### Upgrade
**Important:** Before upgrading, check you have all the `storage` fields in your [production.yaml file](https://github.com/Chocobozzz/PeerTube/blob/develop/support/docker/production/config/production.yaml).
**Important:** Before upgrading, check you have all the `storage` fields in your [production.yaml file](/support/docker/production/config/production.yaml).
Pull the latest images and rerun PeerTube:

View file

@ -238,7 +238,7 @@ to your own administrator password, although it must be 6 characters or more.
Now your instance is up you can:
* Subscribe to the mailing list for PeerTube administrators: https://framalistes.org/sympa/subscribe/peertube-admin
* Add your instance to the public PeerTube instances index if you want to: https://instances.joinpeertube.org/
* Add you instance to the public PeerTube instances index if you want to: https://instances.peertu.be/
* Check [available CLI tools](/support/doc/tools.md)
## Upgrade