diff --git a/client/src/app/+videos/+video-watch/video-watch.component.html b/client/src/app/+videos/+video-watch/video-watch.component.html
index 99103c2c3..c1ba0a755 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.html
+++ b/client/src/app/+videos/+video-watch/video-watch.component.html
@@ -16,6 +16,8 @@
[playlist]="playlist" class="playlist"
(videoFound)="onPlaylistVideoFound($event)"
>
+
+
diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts
index 2392a234c..3152a7003 100644
--- a/client/src/app/core/core.module.ts
+++ b/client/src/app/core/core.module.ts
@@ -5,8 +5,7 @@ import { CommonModule } from '@angular/common'
import { NgModule, Optional, SkipSelf } from '@angular/core'
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
import { PeerTubeSocket } from '@app/core/notification/peertube-socket.service'
-import { HooksService } from '@app/core/plugins/hooks.service'
-import { PluginService } from '@app/core/plugins/plugin.service'
+import { HooksService, PluginService } from '@app/core/plugins'
import { AuthService } from './auth'
import { ConfirmService } from './confirm'
import { CheatSheetComponent } from './hotkeys'
@@ -15,7 +14,7 @@ import { throwIfAlreadyLoaded } from './module-import-guard'
import { Notifier } from './notification'
import { HtmlRendererService, LinkifierService, MarkdownService } from './renderer'
import { RestExtractor, RestService } from './rest'
-import { LoginGuard, RedirectService, UserRightGuard, UnloggedGuard } from './routing'
+import { LoginGuard, RedirectService, UnloggedGuard, UserRightGuard } from './routing'
import { CanDeactivateGuard } from './routing/can-deactivate-guard.service'
import { ServerConfigResolver } from './routing/server-config-resolver.service'
import { ScopedTokensService } from './scoped-tokens'
diff --git a/client/src/app/shared/shared-main/plugins/index.ts b/client/src/app/shared/shared-main/plugins/index.ts
new file mode 100644
index 000000000..f36dab624
--- /dev/null
+++ b/client/src/app/shared/shared-main/plugins/index.ts
@@ -0,0 +1 @@
+export * from './plugin-placeholder.component'
diff --git a/client/src/app/shared/shared-main/plugins/plugin-placeholder.component.ts b/client/src/app/shared/shared-main/plugins/plugin-placeholder.component.ts
new file mode 100644
index 000000000..93ba9fb9b
--- /dev/null
+++ b/client/src/app/shared/shared-main/plugins/plugin-placeholder.component.ts
@@ -0,0 +1,15 @@
+import { Component, Input } from '@angular/core'
+import { PluginElementPlaceholder } from '@shared/models'
+
+@Component({
+ selector: 'my-plugin-placeholder',
+ template: '
'
+})
+
+export class PluginPlaceholderComponent {
+ @Input() pluginId: PluginElementPlaceholder
+
+ getId () {
+ return 'plugin-placeholder-' + this.pluginId
+ }
+}
diff --git a/client/src/app/shared/shared-main/shared-main.module.ts b/client/src/app/shared/shared-main/shared-main.module.ts
index 16d230f46..772198cb2 100644
--- a/client/src/app/shared/shared-main/shared-main.module.ts
+++ b/client/src/app/shared/shared-main/shared-main.module.ts
@@ -33,6 +33,7 @@ import { DateToggleComponent } from './date'
import { FeedComponent } from './feeds'
import { LoaderComponent, SmallLoaderComponent } from './loaders'
import { HelpComponent, ListOverflowComponent, SimpleSearchInputComponent, TopMenuDropdownComponent } from './misc'
+import { PluginPlaceholderComponent } from './plugins'
import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users'
import { RedundancyService, VideoImportService, VideoOwnershipService, VideoService } from './video'
import { VideoCaptionService } from './video-caption'
@@ -92,7 +93,9 @@ import { VideoChannelService } from './video-channel'
SimpleSearchInputComponent,
UserQuotaComponent,
- UserNotificationsComponent
+ UserNotificationsComponent,
+
+ PluginPlaceholderComponent
],
exports: [
@@ -144,7 +147,9 @@ import { VideoChannelService } from './video-channel'
SimpleSearchInputComponent,
UserQuotaComponent,
- UserNotificationsComponent
+ UserNotificationsComponent,
+
+ PluginPlaceholderComponent
],
providers: [
diff --git a/shared/models/plugins/index.ts b/shared/models/plugins/index.ts
index 740083f0e..03b27f907 100644
--- a/shared/models/plugins/index.ts
+++ b/shared/models/plugins/index.ts
@@ -7,6 +7,7 @@ export * from './peertube-plugin-index.model'
export * from './peertube-plugin-latest-version.model'
export * from './peertube-plugin.model'
export * from './plugin-client-scope.type'
+export * from './plugin-element-placeholder.type'
export * from './plugin-package-json.model'
export * from './plugin-playlist-privacy-manager.model'
export * from './plugin-settings-manager.model'
diff --git a/shared/models/plugins/plugin-element-placeholder.type.ts b/shared/models/plugins/plugin-element-placeholder.type.ts
new file mode 100644
index 000000000..129099c62
--- /dev/null
+++ b/shared/models/plugins/plugin-element-placeholder.type.ts
@@ -0,0 +1 @@
+export type PluginElementPlaceholder = 'player-next'
diff --git a/support/doc/plugins/guide.md b/support/doc/plugins/guide.md
index e30d95fc9..81999bf32 100644
--- a/support/doc/plugins/guide.md
+++ b/support/doc/plugins/guide.md
@@ -15,7 +15,7 @@
- [Add custom routes](#add-custom-routes)
- [Add external auth methods](#add-external-auth-methods)
- [Add new transcoding profiles](#add-new-transcoding-profiles)
- - [Helpers](#helpers)
+ - [Server helpers](#server-helpers)
- [Client API (themes & plugins)](#client-api-themes--plugins)
- [Plugin static route](#plugin-static-route)
- [Notifier](#notifier)
@@ -26,6 +26,7 @@
- [Get server config](#get-server-config)
- [Add custom fields to video form](#add-custom-fields-to-video-form)
- [Register settings script](#register-settings-script)
+ - [HTML placeholder elements](#html-placeholder-elements)
- [Publishing](#publishing)
- [Write a plugin/theme](#write-a-plugintheme)
- [Clone the quickstart repository](#clone-the-quickstart-repository)
@@ -424,7 +425,7 @@ async function register ({
During live transcode input options are applied once for each target resolution.
Plugins are responsible for detecting such situation and applying input options only once if necessary.
-### Helpers
+#### Server helpers
PeerTube provides your plugin some helpers. For example:
@@ -628,6 +629,21 @@ async function register ({ registerSettingsScript }) {
}
```
+#### HTML placeholder elements
+
+PeerTube provides some HTML id so plugins can easily insert their own element:
+
+```
+async function register (...) {
+ const elem = document.createElement('div')
+ elem.className = 'hello-world-h4'
+ elem.innerHTML = '
Hello everybody! This is an element next to the player
'
+
+ document.getElementById('plugin-placeholder-player-next').appendChild(elem)
+}
+```
+
+See the complete list on https://docs.joinpeertube.org/api-plugins
### Publishing