diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index ca563edf6..b5d7ede72 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -2,13 +2,15 @@
Interested in contributing? Awesome!
-**Quick Links:**
+**This guide will present you the following contribution topics:**
* [Translate](#translate)
* [Give your feedback](#give-your-feedback)
* [Write documentation](#write-documentation)
* [Develop](#develop)
-
+ * [Improve the website](#improve-the-website)
+ * [Troubleshooting](#troubleshooting)
+ * [Tutorials](#tutorials)
## Translate
@@ -37,6 +39,15 @@ Some hints:
* Models sent/received by the controllers are defined in [/shared/models](/shared/models) directory
+## Improve the website
+
+PeerTube's website is [joinpeertube.org](https://joinpeertube.org), where people can learn about the project and how it works – note that it is not a PeerTube instance, but rather the project's homepage.
+
+You can help us improve it too!
+
+It is not hosted on GitHub but on [Framasoft](https://framasoft.org/)'s own [GitLab](https://about.gitlab.com/) instance, [FramaGit](https://framagit.org): https://framagit.org/framasoft/peertube/joinpeertube
+
+
## Develop
Don't hesitate to talk about features you want to develop by creating/commenting an issue
@@ -122,37 +133,7 @@ and the web server is automatically restarted.
$ npm run dev
```
-Depending on your OS, you may face the following error :
-```
-$ [nodemon] Internal watch failed: ENOSPC: no space left on device, watch '/PeerTube/dist'
-```
-
-This is due to your system's limit on the number of files you can monitor for live-checking changes. For example, Ubuntu uses inotify and this limit is set to 8192. Then you need to change this limit :
-```
-echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
-```
-
-See more information here : https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers
-
-### Configurations for VPS
-
-If you want to develop using a Virtual Private Server, you will need to configure the url for the API and the hostname. First, you need to edit the [client/src/environments/environment.hmr.ts](client/src/environments/environment.hmr.ts) file by replacing the `localhost` in the `apiUrl` field with the address of your VPS. Thus, the [Hot Module Replacement](https://webpack.js.org/concepts/hot-module-replacement/) from Webpack will be set up for developping with live-reload.
-
-Next, you will need to edit the [config/default.yaml](config/default.yaml) file. Just replace the `localhost` with your VPS address in the following `hostname` fields :
-```
-listen:
- hostname: 'my-vps-address.net'
- port: 9000
-
-webserver:
- https: false
- hostname: 'my-vps-address.net'
- port: 9000
-```
-
-Then, you just need to listen to `https://my-vps-address.net:3000/` in your web browser.
-
-### Federation
+### Testing the federation of PeerTube servers
Create a PostgreSQL user **with the same name as your username** in order to avoid using the *postgres* user.
Then, we can create the databases (if they don't already exist):
@@ -206,3 +187,11 @@ $ npm run mocha -- --exit --require ts-node/register/type-check --bail server/te
Instance configurations are in `config/test-{1,2,3,4,5,6}.yaml`.
Note that only instance 2 has transcoding enabled.
+
+### Troubleshooting
+
+Please check out the issues and [list of common errors](https://docs.joinpeertube.org/lang/en/devdocs/troubleshooting.html).
+
+### Tutorials
+
+Please check out the related section in the [development documentation](https://docs.joinpeertube.org/lang/en/devdocs/index.html#tutorials). Contribute tutorials at [framagit.org/framasoft/peertube/documentation](https://framagit.org/framasoft/peertube/documentation).
diff --git a/README.md b/README.md
index ab811d276..3303d8a32 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
Website
| Join an instance
- | Create one
+ | Create an instance
| Chat with us
@@ -75,7 +75,7 @@ Just upload your videos, and be sure they will stream anywhere. Add a descriptio
Keep in touch with video creators
-Follow your favorite channels from PeerTube or really any other place. No need to have an account on the instance you watched a video to follow its author, you can do all of that from the Fediverse (Mastodon, Pleroma and plenty others), or just with good ol' RSS.
+Follow your favorite channels from PeerTube or really any other place. No need to have an account on the instance you watched a video to follow its author, you can do all of that from the Fediverse (Mastodon, Pleroma, and plenty others), or just with good ol' RSS.
---
@@ -121,6 +121,24 @@ enough because one video could become popular and overload the server. That is
why we need to use a P2P protocol to limit the server load. Thanks to
[WebTorrent](https://github.com/feross/webtorrent), we can make BitTorrent inside the web browser, as of today.
+:raised_hands: Contributing
+----------------------------------------------------------------
+
+You don't need to be a coder to help!
+
+You can give us your feedback, report bugs, help us translate PeerTube, write documentation, and more. Check out the [contributing
+guide](/.github/CONTRIBUTING.md) to know how, it takes less than 2 minutes to get started. :wink:
+
+You can also join the cheerful bunch that makes our community:
+
+* Chat:
+ * IRC : **[#peertube on chat.freenode.net:6697](https://kiwiirc.com/client/irc.freenode.net/#peertube)**
+ * Matrix (bridged on the IRC channel) : **[#peertube:matrix.org](https://matrix.to/#/#peertube:matrix.org)**
+* Forum:
+ * Framacolibri: [https://framacolibri.org/c/peertube](https://framacolibri.org/c/peertube)
+
+Feel free to reach out if you have any questions or ideas! :speech_balloon:
+
:package: Create your own instance
----------------------------------------------------------------
@@ -137,20 +155,6 @@ See the [production guide](/support/doc/production.md), which is the recommended
See the [community packages](https://docs.joinpeertube.org/lang/en/docs/install.html), which cover various platforms (including [YunoHost](https://install-app.yunohost.org/?app=peertube) and [Docker](/support/doc/docker.md)).
-:wrench: Contribute/Translate/Test
-----------------------------------------------------------------
-
-*Spoiler alert*: you don't need to be a coder to help!
-
-See the [contributing
-guide](/.github/CONTRIBUTING.md). Or simply join the cheerful bunch that makes our community:
-
- * Chat:
- * IRC : **[#peertube on chat.freenode.net:6697](https://kiwiirc.com/client/irc.freenode.net/#peertube)**
- * Matrix (bridged on the IRC channel) : **[#peertube:matrix.org](https://matrix.to/#/#peertube:matrix.org)**
- * Forum:
- * Framacolibri: [https://framacolibri.org/c/peertube](https://framacolibri.org/c/peertube)
-
:book: Documentation
----------------------------------------------------------------
@@ -179,9 +183,8 @@ See [ARCHITECTURE.md](/ARCHITECTURE.md) for a more detailed explanation of the a
#### Backend
* REST API:
- * Quick Start: [/support/doc/api/quickstart.md](/support/doc/api/quickstart.md)
- * Swagger/OpenAPI schema: [/support/doc/api/openapi.yaml](/support/doc/api/openapi.yaml)
- * HTML explorer: [/support/doc/api/html/index.html](https://htmlpreview.github.io/?https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/api/html/index.html)
+ * OpenAPI 3.0.0 schema: [/support/doc/api/openapi.yaml](/support/doc/api/openapi.yaml)
+ * HTML explorer: [docs.joinpeertube.org/api.html](http://docs.joinpeertube.org/api.html)
* Servers communicate with each other with [Activity
Pub](https://www.w3.org/TR/activitypub/).
* Each server has its own users who query it (search videos, query where the
diff --git a/client/package.json b/client/package.json
index 6f8c62402..a14978998 100644
--- a/client/package.json
+++ b/client/package.json
@@ -63,23 +63,23 @@
"setupTestFrameworkScriptFile": "/src/setupJest.ts"
},
"devDependencies": {
- "@angular-devkit/build-angular": "^0.8.3",
- "@angular/animations": "~6.1.4",
- "@angular/cli": "~6.2.3",
- "@angular/common": "~6.1.4",
- "@angular/compiler": "~6.1.4",
- "@angular/compiler-cli": "~6.1.4",
- "@angular/core": "~6.1.4",
- "@angular/forms": "~6.1.4",
- "@angular/http": "~6.1.4",
- "@angular/language-service": "~6.1.4",
- "@angular/platform-browser": "~6.1.4",
- "@angular/platform-browser-dynamic": "~6.1.4",
- "@angular/router": "~6.1.4",
- "@angular/service-worker": "~6.1.4",
+ "@angular-devkit/build-angular": "~0.10.0",
+ "@angular/animations": "~7.0.2",
+ "@angular/cli": "~7.0.4",
+ "@angular/common": "~7.0.2",
+ "@angular/compiler": "~7.0.2",
+ "@angular/compiler-cli": "~7.0.2",
+ "@angular/core": "~7.0.2",
+ "@angular/forms": "~7.0.2",
+ "@angular/http": "~7.0.2",
+ "@angular/language-service": "~7.0.2",
+ "@angular/platform-browser": "~7.0.2",
+ "@angular/platform-browser-dynamic": "~7.0.2",
+ "@angular/router": "~7.0.2",
+ "@angular/service-worker": "~7.0.2",
"@angularclass/hmr": "^2.1.3",
"@neos21/bootstrap3-glyphicons": "^1.0.1",
- "@ng-bootstrap/ng-bootstrap": "^3.1.0",
+ "@ng-bootstrap/ng-bootstrap": "^4.0.0",
"@ngx-loading-bar/core": "^2.2.0",
"@ngx-loading-bar/http-client": "^2.2.0",
"@ngx-loading-bar/router": "^2.2.0",
@@ -129,7 +129,6 @@
"ngx-clipboard": "11.1.7",
"ngx-pipes": "^2.1.7",
"ngx-qrcode2": "^0.0.9",
- "ngx-textarea-autosize": "^2.0.0",
"node-sass": "^4.9.3",
"npm-font-source-sans-pro": "^1.0.2",
"path-browserify": "^1.0.0",
@@ -139,17 +138,17 @@
"purify-css": "^1.2.5",
"purifycss-webpack": "^0.7.0",
"raw-loader": "^0.5.1",
- "rxjs": "^6.1.0",
+ "rxjs": "^6.3.3",
"sanitize-html": "^1.18.4",
"sass-loader": "^7.1.0",
- "sass-resources-loader": "^1.2.1",
+ "sass-resources-loader": "^2.0.0",
"stream-browserify": "^2.0.1",
- "stream-http": "^2.8.3",
+ "stream-http": "^3.0.0",
"terser-webpack-plugin": "^1.1.0",
"ts-jest": "^23.1.4",
"tslint": "^5.7.0",
"tslint-config-standard": "^8.0.1",
- "typescript": "2.9",
+ "typescript": "3.1.6",
"video.js": "^7",
"videojs-contextmenu-ui": "^5.0.0",
"videojs-dock": "^2.0.2",
diff --git a/client/src/app/+admin/users/user-edit/user-edit.ts b/client/src/app/+admin/users/user-edit/user-edit.ts
index 99ce5804b..0b3511e8e 100644
--- a/client/src/app/+admin/users/user-edit/user-edit.ts
+++ b/client/src/app/+admin/users/user-edit/user-edit.ts
@@ -4,10 +4,10 @@ import { USER_ROLE_LABELS, VideoResolution } from '../../../../../../shared'
import { ConfigService } from '@app/+admin/config/shared/config.service'
export abstract class UserEdit extends FormReactive {
-
videoQuotaOptions: { value: string, label: string }[] = []
videoQuotaDailyOptions: { value: string, label: string }[] = []
roles = Object.keys(USER_ROLE_LABELS).map(key => ({ value: key.toString(), label: USER_ROLE_LABELS[key] }))
+ username: string
protected abstract serverService: ServerService
protected abstract configService: ConfigService
diff --git a/client/src/app/+admin/users/user-list/user-list.component.html b/client/src/app/+admin/users/user-list/user-list.component.html
index eb8d30e17..5684004a5 100644
--- a/client/src/app/+admin/users/user-list/user-list.component.html
+++ b/client/src/app/+admin/users/user-list/user-list.component.html
@@ -86,4 +86,4 @@
-
+
diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts
index 3859af9ff..31e783622 100644
--- a/client/src/app/+admin/users/user-list/user-list.component.ts
+++ b/client/src/app/+admin/users/user-list/user-list.component.ts
@@ -66,7 +66,7 @@ export class UserListComponent extends RestTable implements OnInit {
this.userBanModal.openModal(users)
}
- onUsersBanned () {
+ onUserChanged () {
this.loadData()
}
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts
index ccdd9a3dc..4dc65dd99 100644
--- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts
+++ b/client/src/app/+my-account/my-account-video-channels/my-account-video-channel-edit.ts
@@ -4,7 +4,11 @@ import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
export abstract class MyAccountVideoChannelEdit extends FormReactive {
// We need it even in the create component because it's used in the edit template
videoChannelToUpdate: VideoChannel
+ instanceHost: string
abstract isCreation (): boolean
abstract getFormButtonTitle (): string
+
+ // FIXME: We need this method so angular does not complain in the child template
+ onAvatarChange (formData: FormData) { /* empty */ }
}
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
index 800d97b7f..1f0744fb1 100644
--- 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
@@ -25,7 +25,7 @@ import { ScreenService } from '@app/shared/misc/screen.service'
export class VideoChannelVideosComponent extends AbstractVideoList implements OnInit, OnDestroy {
titlePage: string
marginContent = false // Disable margin
- currentRoute = '/video-channel/videos'
+ currentRoute = '/video-channels/videos'
loadOnInit = false
private videoChannel: VideoChannel
@@ -55,7 +55,7 @@ export class VideoChannelVideosComponent extends AbstractVideoList implements On
this.videoChannelSub = this.videoChannelService.videoChannelLoaded
.subscribe(videoChannel => {
this.videoChannel = videoChannel
- this.currentRoute = '/video-channel/' + this.videoChannel.uuid + '/videos'
+ this.currentRoute = '/video-channels/' + this.videoChannel.uuid + '/videos'
this.reloadVideos()
this.generateSyndicationList()
diff --git a/client/src/app/header/header.component.scss b/client/src/app/header/header.component.scss
index bd03c338a..2f9820665 100644
--- a/client/src/app/header/header.component.scss
+++ b/client/src/app/header/header.component.scss
@@ -50,7 +50,7 @@
.icon.icon-upload {
@include icon(22px);
- background-image: url('../../assets/images/header/upload.svg');
+ background-image: url('../../assets/images/header/upload-white.svg');
height: 24px;
vertical-align: middle;
margin-right: 6px;
diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss
index a842765ba..b271ebfd2 100644
--- a/client/src/app/menu/menu.component.scss
+++ b/client/src/app/menu/menu.component.scss
@@ -131,10 +131,14 @@ menu {
transition: background-color .1s ease-in-out;
@include disable-default-a-behaviour;
- &:hover, &.focus-visible {
+ &.active {
background-color: rgba(255, 255, 255, 0.15);
}
+ &:hover, &.focus-visible {
+ background-color: rgba(255, 255, 255, 0.10);
+ }
+
.icon {
@include icon(22px);
diff --git a/client/src/app/shared/forms/index.ts b/client/src/app/shared/forms/index.ts
index 41c321c4c..8febbfee9 100644
--- a/client/src/app/shared/forms/index.ts
+++ b/client/src/app/shared/forms/index.ts
@@ -1,3 +1,4 @@
export * from './form-validators'
export * from './form-reactive'
export * from './reactive-file.component'
+export * from './textarea-autoresize.directive'
diff --git a/client/src/app/shared/forms/textarea-autoresize.directive.ts b/client/src/app/shared/forms/textarea-autoresize.directive.ts
new file mode 100644
index 000000000..f8c855c16
--- /dev/null
+++ b/client/src/app/shared/forms/textarea-autoresize.directive.ts
@@ -0,0 +1,25 @@
+// Thanks: https://github.com/evseevdev/ngx-textarea-autosize
+import { AfterViewInit, Directive, ElementRef, HostBinding, HostListener } from '@angular/core'
+
+@Directive({
+ selector: 'textarea[myAutoResize]'
+})
+export class TextareaAutoResizeDirective implements AfterViewInit {
+ @HostBinding('attr.rows') rows = '1'
+ @HostBinding('style.overflow') overflow = 'hidden'
+
+ constructor (private elem: ElementRef) { }
+
+ public ngAfterViewInit () {
+ this.resize()
+ }
+
+ @HostListener('input')
+ resize () {
+ const textarea = this.elem.nativeElement as HTMLTextAreaElement
+ // Reset textarea height to auto that correctly calculate the new height
+ textarea.style.height = 'auto'
+ // Set new height
+ textarea.style.height = `${textarea.scrollHeight}px`
+ }
+}
diff --git a/client/src/app/shared/misc/from-now.pipe.ts b/client/src/app/shared/misc/from-now.pipe.ts
index 33e6d25fe..00b5be6c9 100644
--- a/client/src/app/shared/misc/from-now.pipe.ts
+++ b/client/src/app/shared/misc/from-now.pipe.ts
@@ -7,8 +7,9 @@ export class FromNowPipe implements PipeTransform {
constructor (private i18n: I18n) { }
- transform (value: number) {
- const seconds = Math.floor((Date.now() - value) / 1000)
+ transform (arg: number | Date | string) {
+ const argDate = new Date(arg)
+ const seconds = Math.floor((Date.now() - argDate.getTime()) / 1000)
let interval = Math.floor(seconds / 31536000)
if (interval > 1) {
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts
index 0ec2a9b15..a2fa27b72 100644
--- a/client/src/app/shared/shared.module.ts
+++ b/client/src/app/shared/shared.module.ts
@@ -37,13 +37,15 @@ import {
LoginValidatorsService,
ReactiveFileComponent,
ResetPasswordValidatorsService,
+ TextareaAutoResizeDirective,
UserValidatorsService,
VideoAbuseValidatorsService,
+ VideoAcceptOwnershipValidatorsService,
VideoBlacklistValidatorsService,
+ VideoChangeOwnershipValidatorsService,
VideoChannelValidatorsService,
VideoCommentValidatorsService,
- VideoValidatorsService,
- VideoChangeOwnershipValidatorsService, VideoAcceptOwnershipValidatorsService
+ VideoValidatorsService
} from '@app/shared/forms'
import { I18nPrimengCalendarService } from '@app/shared/i18n/i18n-primeng-calendar'
import { ScreenService } from '@app/shared/misc/screen.service'
@@ -53,7 +55,7 @@ import { PeertubeCheckboxComponent } from '@app/shared/forms/peertube-checkbox.c
import { VideoImportService } from '@app/shared/video-import/video-import.service'
import { ActionDropdownComponent } from '@app/shared/buttons/action-dropdown.component'
import { NgbDropdownModule, NgbModalModule, NgbPopoverModule, NgbTabsetModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
-import { SubscribeButtonComponent, RemoteSubscribeComponent, UserSubscriptionService } from '@app/shared/user-subscription'
+import { RemoteSubscribeComponent, SubscribeButtonComponent, UserSubscriptionService } from '@app/shared/user-subscription'
import { InstanceFeaturesTableComponent } from '@app/shared/instance/instance-features-table.component'
import { OverviewService } from '@app/shared/overview'
import { UserBanModalComponent } from '@app/shared/moderation'
@@ -92,6 +94,7 @@ import { BlocklistService } from '@app/shared/blocklist'
FromNowPipe,
MarkdownTextareaComponent,
InfiniteScrollerDirective,
+ TextareaAutoResizeDirective,
HelpComponent,
ReactiveFileComponent,
PeertubeCheckboxComponent,
@@ -129,6 +132,7 @@ import { BlocklistService } from '@app/shared/blocklist'
ActionDropdownComponent,
MarkdownTextareaComponent,
InfiniteScrollerDirective,
+ TextareaAutoResizeDirective,
HelpComponent,
ReactiveFileComponent,
PeertubeCheckboxComponent,
diff --git a/client/src/app/shared/video/video-miniature.component.html b/client/src/app/shared/video/video-miniature.component.html
index 277a0cf35..2c635fa2f 100644
--- a/client/src/app/shared/video/video-miniature.component.html
+++ b/client/src/app/shared/video/video-miniature.component.html
@@ -7,10 +7,10 @@
class="video-miniature-name"
[routerLink]="[ '/videos/watch', video.uuid ]" [attr.title]="video.name" [ngClass]="{ 'blur-filter': isVideoBlur }"
>
- {{ video.name }}
-
Unlisted
Private
+
+ {{ video.name }}
{{ video.publishedAt | myFromNow }} - {{ video.views | myNumberFormatter }} views
diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts
index 65297d7a1..55844f988 100644
--- a/client/src/app/shared/video/video.service.ts
+++ b/client/src/app/shared/video/video.service.ts
@@ -6,11 +6,11 @@ import { Video as VideoServerModel, VideoDetails as VideoDetailsServerModel } fr
import { ResultList } from '../../../../../shared/models/result-list.model'
import {
UserVideoRate,
+ UserVideoRateType,
UserVideoRateUpdate,
VideoConstant,
VideoFilter,
VideoPrivacy,
- VideoRateType,
VideoUpdate
} from '../../../../../shared/models/videos'
import { FeedFormat } from '../../../../../shared/models/feeds/feed-format.enum'
@@ -332,7 +332,7 @@ export class VideoService implements VideosProvider {
return privacies
}
- private setVideoRate (id: number, rateType: VideoRateType) {
+ private setVideoRate (id: number, rateType: UserVideoRateType) {
const url = VideoService.BASE_VIDEO_URL + id + '/rate'
const body: UserVideoRateUpdate = {
rating: rateType
diff --git a/client/src/app/videos/+video-watch/comment/video-comment-add.component.html b/client/src/app/videos/+video-watch/comment/video-comment-add.component.html
index b58a56596..d8a7a78c4 100644
--- a/client/src/app/videos/+video-watch/comment/video-comment-add.component.html
+++ b/client/src/app/videos/+video-watch/comment/video-comment-add.component.html
@@ -3,7 +3,7 @@