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 @@

- PeerTube - + PeerTube +

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 @@ Avatar
-