aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib')
-rw-r--r--server/lib/activitypub/actor.ts7
-rw-r--r--server/lib/activitypub/audience.ts2
-rw-r--r--server/lib/activitypub/process/process-accept.ts4
-rw-r--r--server/lib/activitypub/process/process-delete.ts2
-rw-r--r--server/lib/activitypub/process/process-follow.ts14
-rw-r--r--server/lib/activitypub/process/process-reject.ts2
-rw-r--r--server/lib/activitypub/process/process-undo.ts4
-rw-r--r--server/lib/activitypub/process/process-update.ts20
-rw-r--r--server/lib/activitypub/send/send-delete.ts2
-rw-r--r--server/lib/activitypub/send/send-view.ts2
-rw-r--r--server/lib/activitypub/send/utils.ts12
-rw-r--r--server/lib/auth/oauth-model.ts4
-rw-r--r--server/lib/client-html.ts33
-rw-r--r--server/lib/config.ts255
-rw-r--r--server/lib/job-queue/handlers/activitypub-follow.ts20
-rw-r--r--server/lib/job-queue/handlers/activitypub-refresher.ts8
-rw-r--r--server/lib/job-queue/handlers/actor-keys.ts2
-rw-r--r--server/lib/job-queue/handlers/utils/activitypub-http-utils.ts8
-rw-r--r--server/lib/job-queue/handlers/video-file-import.ts2
-rw-r--r--server/lib/job-queue/handlers/video-import.ts7
-rw-r--r--server/lib/job-queue/handlers/video-live-ending.ts2
-rw-r--r--server/lib/job-queue/handlers/video-transcoding.ts4
-rw-r--r--server/lib/job-queue/handlers/video-views.ts4
-rw-r--r--server/lib/live-manager.ts102
-rw-r--r--server/lib/moderation.ts6
-rw-r--r--server/lib/notifier.ts4
-rw-r--r--server/lib/plugins/hooks.ts6
-rw-r--r--server/lib/plugins/plugin-helpers-builder.ts6
-rw-r--r--server/lib/plugins/plugin-index.ts20
-rw-r--r--server/lib/plugins/plugin-manager.ts14
-rw-r--r--server/lib/plugins/register-helpers.ts6
-rw-r--r--server/lib/redundancy.ts12
-rw-r--r--server/lib/schedulers/actor-follow-scheduler.ts4
-rw-r--r--server/lib/schedulers/auto-follow-index-instances.ts2
-rw-r--r--server/lib/schedulers/remove-old-history-scheduler.ts2
-rw-r--r--server/lib/schedulers/youtube-dl-update-scheduler.ts6
-rw-r--r--server/lib/server-config-manager.ts304
-rw-r--r--server/lib/stat-manager.ts4
-rw-r--r--server/lib/transcoding/video-transcoding-profiles.ts (renamed from server/lib/video-transcoding-profiles.ts)8
-rw-r--r--server/lib/transcoding/video-transcoding.ts (renamed from server/lib/video-transcoding.ts)35
-rw-r--r--server/lib/user.ts9
-rw-r--r--server/lib/video-channel.ts4
-rw-r--r--server/lib/video-comment.ts2
-rw-r--r--server/lib/video.ts2
44 files changed, 525 insertions, 453 deletions
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts
index 5fe7381c9..1bcee7ef9 100644
--- a/server/lib/activitypub/actor.ts
+++ b/server/lib/activitypub/actor.ts
@@ -20,8 +20,8 @@ import { getUrlFromWebfinger } from '../../helpers/webfinger'
20import { MIMETYPES, WEBSERVER } from '../../initializers/constants' 20import { MIMETYPES, WEBSERVER } from '../../initializers/constants'
21import { sequelizeTypescript } from '../../initializers/database' 21import { sequelizeTypescript } from '../../initializers/database'
22import { AccountModel } from '../../models/account/account' 22import { AccountModel } from '../../models/account/account'
23import { ActorImageModel } from '../../models/account/actor-image' 23import { ActorModel } from '../../models/actor/actor'
24import { ActorModel } from '../../models/activitypub/actor' 24import { ActorImageModel } from '../../models/actor/actor-image'
25import { ServerModel } from '../../models/server/server' 25import { ServerModel } from '../../models/server/server'
26import { VideoChannelModel } from '../../models/video/video-channel' 26import { VideoChannelModel } from '../../models/video/video-channel'
27import { 27import {
@@ -132,12 +132,11 @@ async function getOrCreateActorAndServerAndModel (
132 return actorRefreshed 132 return actorRefreshed
133} 133}
134 134
135function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { 135function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string) {
136 return new ActorModel({ 136 return new ActorModel({
137 type, 137 type,
138 url, 138 url,
139 preferredUsername, 139 preferredUsername,
140 uuid,
141 publicKey: null, 140 publicKey: null,
142 privateKey: null, 141 privateKey: null,
143 followersCount: 0, 142 followersCount: 0,
diff --git a/server/lib/activitypub/audience.ts b/server/lib/activitypub/audience.ts
index 2986714d3..d0558f191 100644
--- a/server/lib/activitypub/audience.ts
+++ b/server/lib/activitypub/audience.ts
@@ -1,7 +1,7 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActivityAudience } from '../../../shared/models/activitypub' 2import { ActivityAudience } from '../../../shared/models/activitypub'
3import { ACTIVITY_PUB } from '../../initializers/constants' 3import { ACTIVITY_PUB } from '../../initializers/constants'
4import { ActorModel } from '../../models/activitypub/actor' 4import { ActorModel } from '../../models/actor/actor'
5import { VideoModel } from '../../models/video/video' 5import { VideoModel } from '../../models/video/video'
6import { VideoShareModel } from '../../models/video/video-share' 6import { VideoShareModel } from '../../models/video/video-share'
7import { MActorFollowersUrl, MActorLight, MActorUrl, MCommentOwner, MCommentOwnerVideo, MVideoId } from '../../types/models' 7import { MActorFollowersUrl, MActorLight, MActorUrl, MCommentOwner, MCommentOwnerVideo, MVideoId } from '../../types/models'
diff --git a/server/lib/activitypub/process/process-accept.ts b/server/lib/activitypub/process/process-accept.ts
index 1799829f8..8ad470cf4 100644
--- a/server/lib/activitypub/process/process-accept.ts
+++ b/server/lib/activitypub/process/process-accept.ts
@@ -1,8 +1,8 @@
1import { ActivityAccept } from '../../../../shared/models/activitypub' 1import { ActivityAccept } from '../../../../shared/models/activitypub'
2import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 2import { ActorFollowModel } from '../../../models/actor/actor-follow'
3import { addFetchOutboxJob } from '../actor'
4import { APProcessorOptions } from '../../../types/activitypub-processor.model' 3import { APProcessorOptions } from '../../../types/activitypub-processor.model'
5import { MActorDefault, MActorSignature } from '../../../types/models' 4import { MActorDefault, MActorSignature } from '../../../types/models'
5import { addFetchOutboxJob } from '../actor'
6 6
7async function processAcceptActivity (options: APProcessorOptions<ActivityAccept>) { 7async function processAcceptActivity (options: APProcessorOptions<ActivityAccept>) {
8 const { byActor: targetActor, inboxActor } = options 8 const { byActor: targetActor, inboxActor } = options
diff --git a/server/lib/activitypub/process/process-delete.ts b/server/lib/activitypub/process/process-delete.ts
index 88a968318..20214246c 100644
--- a/server/lib/activitypub/process/process-delete.ts
+++ b/server/lib/activitypub/process/process-delete.ts
@@ -2,7 +2,7 @@ import { ActivityDelete } from '../../../../shared/models/activitypub'
2import { retryTransactionWrapper } from '../../../helpers/database-utils' 2import { retryTransactionWrapper } from '../../../helpers/database-utils'
3import { logger } from '../../../helpers/logger' 3import { logger } from '../../../helpers/logger'
4import { sequelizeTypescript } from '../../../initializers/database' 4import { sequelizeTypescript } from '../../../initializers/database'
5import { ActorModel } from '../../../models/activitypub/actor' 5import { ActorModel } from '../../../models/actor/actor'
6import { VideoModel } from '../../../models/video/video' 6import { VideoModel } from '../../../models/video/video'
7import { VideoCommentModel } from '../../../models/video/video-comment' 7import { VideoCommentModel } from '../../../models/video/video-comment'
8import { VideoPlaylistModel } from '../../../models/video/video-playlist' 8import { VideoPlaylistModel } from '../../../models/video/video-playlist'
diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts
index 38d684512..9009c6469 100644
--- a/server/lib/activitypub/process/process-follow.ts
+++ b/server/lib/activitypub/process/process-follow.ts
@@ -1,17 +1,17 @@
1import { getServerActor } from '@server/models/application/application'
1import { ActivityFollow } from '../../../../shared/models/activitypub' 2import { ActivityFollow } from '../../../../shared/models/activitypub'
3import { getAPId } from '../../../helpers/activitypub'
2import { retryTransactionWrapper } from '../../../helpers/database-utils' 4import { retryTransactionWrapper } from '../../../helpers/database-utils'
3import { logger } from '../../../helpers/logger' 5import { logger } from '../../../helpers/logger'
4import { sequelizeTypescript } from '../../../initializers/database'
5import { ActorModel } from '../../../models/activitypub/actor'
6import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
7import { sendAccept, sendReject } from '../send'
8import { Notifier } from '../../notifier'
9import { getAPId } from '../../../helpers/activitypub'
10import { CONFIG } from '../../../initializers/config' 6import { CONFIG } from '../../../initializers/config'
7import { sequelizeTypescript } from '../../../initializers/database'
8import { ActorModel } from '../../../models/actor/actor'
9import { ActorFollowModel } from '../../../models/actor/actor-follow'
11import { APProcessorOptions } from '../../../types/activitypub-processor.model' 10import { APProcessorOptions } from '../../../types/activitypub-processor.model'
12import { MActorFollowActors, MActorSignature } from '../../../types/models' 11import { MActorFollowActors, MActorSignature } from '../../../types/models'
12import { Notifier } from '../../notifier'
13import { autoFollowBackIfNeeded } from '../follow' 13import { autoFollowBackIfNeeded } from '../follow'
14import { getServerActor } from '@server/models/application/application' 14import { sendAccept, sendReject } from '../send'
15 15
16async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) { 16async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) {
17 const { activity, byActor } = options 17 const { activity, byActor } = options
diff --git a/server/lib/activitypub/process/process-reject.ts b/server/lib/activitypub/process/process-reject.ts
index 03b669fd9..7f7ab305f 100644
--- a/server/lib/activitypub/process/process-reject.ts
+++ b/server/lib/activitypub/process/process-reject.ts
@@ -1,6 +1,6 @@
1import { ActivityReject } from '../../../../shared/models/activitypub/activity' 1import { ActivityReject } from '../../../../shared/models/activitypub/activity'
2import { sequelizeTypescript } from '../../../initializers/database' 2import { sequelizeTypescript } from '../../../initializers/database'
3import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 3import { ActorFollowModel } from '../../../models/actor/actor-follow'
4import { APProcessorOptions } from '../../../types/activitypub-processor.model' 4import { APProcessorOptions } from '../../../types/activitypub-processor.model'
5import { MActor } from '../../../types/models' 5import { MActor } from '../../../types/models'
6 6
diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts
index e520c2f0d..9f031b528 100644
--- a/server/lib/activitypub/process/process-undo.ts
+++ b/server/lib/activitypub/process/process-undo.ts
@@ -4,8 +4,8 @@ import { retryTransactionWrapper } from '../../../helpers/database-utils'
4import { logger } from '../../../helpers/logger' 4import { logger } from '../../../helpers/logger'
5import { sequelizeTypescript } from '../../../initializers/database' 5import { sequelizeTypescript } from '../../../initializers/database'
6import { AccountVideoRateModel } from '../../../models/account/account-video-rate' 6import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
7import { ActorModel } from '../../../models/activitypub/actor' 7import { ActorModel } from '../../../models/actor/actor'
8import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 8import { ActorFollowModel } from '../../../models/actor/actor-follow'
9import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' 9import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy'
10import { VideoShareModel } from '../../../models/video/video-share' 10import { VideoShareModel } from '../../../models/video/video-share'
11import { APProcessorOptions } from '../../../types/activitypub-processor.model' 11import { APProcessorOptions } from '../../../types/activitypub-processor.model'
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts
index 6df9b93b2..6cd9d0fba 100644
--- a/server/lib/activitypub/process/process-update.ts
+++ b/server/lib/activitypub/process/process-update.ts
@@ -1,23 +1,23 @@
1import { isRedundancyAccepted } from '@server/lib/redundancy'
2import { ActorImageType } from '@shared/models'
1import { ActivityUpdate, CacheFileObject, VideoObject } from '../../../../shared/models/activitypub' 3import { ActivityUpdate, CacheFileObject, VideoObject } from '../../../../shared/models/activitypub'
2import { ActivityPubActor } from '../../../../shared/models/activitypub/activitypub-actor' 4import { ActivityPubActor } from '../../../../shared/models/activitypub/activitypub-actor'
5import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object'
6import { isCacheFileObjectValid } from '../../../helpers/custom-validators/activitypub/cache-file'
7import { sanitizeAndCheckVideoTorrentObject } from '../../../helpers/custom-validators/activitypub/videos'
3import { resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers/database-utils' 8import { resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers/database-utils'
4import { logger } from '../../../helpers/logger' 9import { logger } from '../../../helpers/logger'
5import { sequelizeTypescript } from '../../../initializers/database' 10import { sequelizeTypescript } from '../../../initializers/database'
6import { AccountModel } from '../../../models/account/account' 11import { AccountModel } from '../../../models/account/account'
7import { ActorModel } from '../../../models/activitypub/actor' 12import { ActorModel } from '../../../models/actor/actor'
8import { VideoChannelModel } from '../../../models/video/video-channel' 13import { VideoChannelModel } from '../../../models/video/video-channel'
14import { APProcessorOptions } from '../../../types/activitypub-processor.model'
15import { MAccountIdActor, MActorSignature } from '../../../types/models'
9import { getImageInfoIfExists, updateActorImageInstance, updateActorInstance } from '../actor' 16import { getImageInfoIfExists, updateActorImageInstance, updateActorInstance } from '../actor'
10import { getOrCreateVideoAndAccountAndChannel, getOrCreateVideoChannelFromVideoObject, updateVideoFromAP } from '../videos'
11import { sanitizeAndCheckVideoTorrentObject } from '../../../helpers/custom-validators/activitypub/videos'
12import { isCacheFileObjectValid } from '../../../helpers/custom-validators/activitypub/cache-file'
13import { createOrUpdateCacheFile } from '../cache-file' 17import { createOrUpdateCacheFile } from '../cache-file'
14import { forwardVideoRelatedActivity } from '../send/utils'
15import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object'
16import { createOrUpdateVideoPlaylist } from '../playlist' 18import { createOrUpdateVideoPlaylist } from '../playlist'
17import { APProcessorOptions } from '../../../types/activitypub-processor.model' 19import { forwardVideoRelatedActivity } from '../send/utils'
18import { MActorSignature, MAccountIdActor } from '../../../types/models' 20import { getOrCreateVideoAndAccountAndChannel, getOrCreateVideoChannelFromVideoObject, updateVideoFromAP } from '../videos'
19import { isRedundancyAccepted } from '@server/lib/redundancy'
20import { ActorImageType } from '@shared/models'
21 21
22async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate>) { 22async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate>) {
23 const { activity, byActor } = options 23 const { activity, byActor } = options
diff --git a/server/lib/activitypub/send/send-delete.ts b/server/lib/activitypub/send/send-delete.ts
index e0acced18..d31f8c10b 100644
--- a/server/lib/activitypub/send/send-delete.ts
+++ b/server/lib/activitypub/send/send-delete.ts
@@ -2,7 +2,7 @@ import { Transaction } from 'sequelize'
2import { getServerActor } from '@server/models/application/application' 2import { getServerActor } from '@server/models/application/application'
3import { ActivityAudience, ActivityDelete } from '../../../../shared/models/activitypub' 3import { ActivityAudience, ActivityDelete } from '../../../../shared/models/activitypub'
4import { logger } from '../../../helpers/logger' 4import { logger } from '../../../helpers/logger'
5import { ActorModel } from '../../../models/activitypub/actor' 5import { ActorModel } from '../../../models/actor/actor'
6import { VideoCommentModel } from '../../../models/video/video-comment' 6import { VideoCommentModel } from '../../../models/video/video-comment'
7import { VideoShareModel } from '../../../models/video/video-share' 7import { VideoShareModel } from '../../../models/video/video-share'
8import { MActorUrl } from '../../../types/models' 8import { MActorUrl } from '../../../types/models'
diff --git a/server/lib/activitypub/send/send-view.ts b/server/lib/activitypub/send/send-view.ts
index 9254dc7c5..153e94295 100644
--- a/server/lib/activitypub/send/send-view.ts
+++ b/server/lib/activitypub/send/send-view.ts
@@ -2,7 +2,7 @@ import { Transaction } from 'sequelize'
2import { MActorAudience, MVideoImmutable, MVideoUrl } from '@server/types/models' 2import { MActorAudience, MVideoImmutable, MVideoUrl } from '@server/types/models'
3import { ActivityAudience, ActivityView } from '../../../../shared/models/activitypub' 3import { ActivityAudience, ActivityView } from '../../../../shared/models/activitypub'
4import { logger } from '../../../helpers/logger' 4import { logger } from '../../../helpers/logger'
5import { ActorModel } from '../../../models/activitypub/actor' 5import { ActorModel } from '../../../models/actor/actor'
6import { audiencify, getAudience } from '../audience' 6import { audiencify, getAudience } from '../audience'
7import { getLocalVideoViewActivityPubUrl } from '../url' 7import { getLocalVideoViewActivityPubUrl } from '../url'
8import { sendVideoRelatedActivity } from './utils' 8import { sendVideoRelatedActivity } from './utils'
diff --git a/server/lib/activitypub/send/utils.ts b/server/lib/activitypub/send/utils.ts
index 85a9f009d..db0e91b71 100644
--- a/server/lib/activitypub/send/utils.ts
+++ b/server/lib/activitypub/send/utils.ts
@@ -1,14 +1,14 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { getServerActor } from '@server/models/application/application'
3import { ContextType } from '@shared/models/activitypub/context'
2import { Activity, ActivityAudience } from '../../../../shared/models/activitypub' 4import { Activity, ActivityAudience } from '../../../../shared/models/activitypub'
5import { afterCommitIfTransaction } from '../../../helpers/database-utils'
3import { logger } from '../../../helpers/logger' 6import { logger } from '../../../helpers/logger'
4import { ActorModel } from '../../../models/activitypub/actor' 7import { ActorModel } from '../../../models/actor/actor'
5import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 8import { ActorFollowModel } from '../../../models/actor/actor-follow'
9import { MActor, MActorId, MActorLight, MActorWithInboxes, MVideoAccountLight, MVideoId, MVideoImmutable } from '../../../types/models'
6import { JobQueue } from '../../job-queue' 10import { JobQueue } from '../../job-queue'
7import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience' 11import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience'
8import { afterCommitIfTransaction } from '../../../helpers/database-utils'
9import { MActor, MActorId, MActorLight, MActorWithInboxes, MVideoAccountLight, MVideoId, MVideoImmutable } from '../../../types/models'
10import { getServerActor } from '@server/models/application/application'
11import { ContextType } from '@shared/models/activitypub/context'
12 12
13async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { 13async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
14 byActor: MActorLight 14 byActor: MActorLight
diff --git a/server/lib/auth/oauth-model.ts b/server/lib/auth/oauth-model.ts
index b9c69eb2d..ae728d080 100644
--- a/server/lib/auth/oauth-model.ts
+++ b/server/lib/auth/oauth-model.ts
@@ -1,7 +1,7 @@
1import * as express from 'express' 1import * as express from 'express'
2import { AccessDeniedError } from 'oauth2-server' 2import { AccessDeniedError } from 'oauth2-server'
3import { PluginManager } from '@server/lib/plugins/plugin-manager' 3import { PluginManager } from '@server/lib/plugins/plugin-manager'
4import { ActorModel } from '@server/models/activitypub/actor' 4import { ActorModel } from '@server/models/actor/actor'
5import { MOAuthClient } from '@server/types/models' 5import { MOAuthClient } from '@server/types/models'
6import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token' 6import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token'
7import { MUser } from '@server/types/models/user/user' 7import { MUser } from '@server/types/models/user/user'
@@ -9,7 +9,7 @@ import { UserAdminFlag } from '@shared/models/users/user-flag.model'
9import { UserRole } from '@shared/models/users/user-role' 9import { UserRole } from '@shared/models/users/user-role'
10import { logger } from '../../helpers/logger' 10import { logger } from '../../helpers/logger'
11import { CONFIG } from '../../initializers/config' 11import { CONFIG } from '../../initializers/config'
12import { UserModel } from '../../models/account/user' 12import { UserModel } from '../../models/user/user'
13import { OAuthClientModel } from '../../models/oauth/oauth-client' 13import { OAuthClientModel } from '../../models/oauth/oauth-client'
14import { OAuthTokenModel } from '../../models/oauth/oauth-token' 14import { OAuthTokenModel } from '../../models/oauth/oauth-token'
15import { createUserAccountAndChannelAndPlaylist } from '../user' 15import { createUserAccountAndChannelAndPlaylist } from '../user'
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts
index 203bd3893..3c09332b5 100644
--- a/server/lib/client-html.ts
+++ b/server/lib/client-html.ts
@@ -2,12 +2,14 @@ import * as express from 'express'
2import { readFile } from 'fs-extra' 2import { readFile } from 'fs-extra'
3import { join } from 'path' 3import { join } from 'path'
4import validator from 'validator' 4import validator from 'validator'
5import { escapeHTML } from '@shared/core-utils/renderer'
6import { HTMLServerConfig } from '@shared/models'
5import { buildFileLocale, getDefaultLocale, is18nLocale, POSSIBLE_LOCALES } from '../../shared/core-utils/i18n/i18n' 7import { buildFileLocale, getDefaultLocale, is18nLocale, POSSIBLE_LOCALES } from '../../shared/core-utils/i18n/i18n'
6import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' 8import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes'
7import { VideoPlaylistPrivacy, VideoPrivacy } from '../../shared/models/videos' 9import { VideoPlaylistPrivacy, VideoPrivacy } from '../../shared/models/videos'
8import { isTestInstance, sha256 } from '../helpers/core-utils' 10import { isTestInstance, sha256 } from '../helpers/core-utils'
9import { escapeHTML } from '@shared/core-utils/renderer'
10import { logger } from '../helpers/logger' 11import { logger } from '../helpers/logger'
12import { mdToPlainText } from '../helpers/markdown'
11import { CONFIG } from '../initializers/config' 13import { CONFIG } from '../initializers/config'
12import { 14import {
13 ACCEPT_HEADERS, 15 ACCEPT_HEADERS,
@@ -24,7 +26,7 @@ import { VideoChannelModel } from '../models/video/video-channel'
24import { getActivityStreamDuration } from '../models/video/video-format-utils' 26import { getActivityStreamDuration } from '../models/video/video-format-utils'
25import { VideoPlaylistModel } from '../models/video/video-playlist' 27import { VideoPlaylistModel } from '../models/video/video-playlist'
26import { MAccountActor, MChannelActor } from '../types/models' 28import { MAccountActor, MChannelActor } from '../types/models'
27import { mdToPlainText } from '../helpers/markdown' 29import { ServerConfigManager } from './server-config-manager'
28 30
29type Tags = { 31type Tags = {
30 ogType: string 32 ogType: string
@@ -196,11 +198,22 @@ class ClientHtml {
196 } 198 }
197 199
198 static async getAccountHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) { 200 static async getAccountHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) {
199 return this.getAccountOrChannelHTMLPage(() => AccountModel.loadByNameWithHost(nameWithHost), req, res) 201 const accountModelPromise = AccountModel.loadByNameWithHost(nameWithHost)
202 return this.getAccountOrChannelHTMLPage(() => accountModelPromise, req, res)
200 } 203 }
201 204
202 static async getVideoChannelHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) { 205 static async getVideoChannelHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) {
203 return this.getAccountOrChannelHTMLPage(() => VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithHost), req, res) 206 const videoChannelModelPromise = VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithHost)
207 return this.getAccountOrChannelHTMLPage(() => videoChannelModelPromise, req, res)
208 }
209
210 static async getActorHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) {
211 const [ account, channel ] = await Promise.all([
212 AccountModel.loadByNameWithHost(nameWithHost),
213 VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithHost)
214 ])
215
216 return this.getAccountOrChannelHTMLPage(() => Promise.resolve(account || channel), req, res)
204 } 217 }
205 218
206 static async getEmbedHTML () { 219 static async getEmbedHTML () {
@@ -209,11 +222,14 @@ class ClientHtml {
209 if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path] 222 if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path]
210 223
211 const buffer = await readFile(path) 224 const buffer = await readFile(path)
225 const serverConfig = await ServerConfigManager.Instance.getHTMLServerConfig()
212 226
213 let html = buffer.toString() 227 let html = buffer.toString()
214 html = await ClientHtml.addAsyncPluginCSS(html) 228 html = await ClientHtml.addAsyncPluginCSS(html)
215 html = ClientHtml.addCustomCSS(html) 229 html = ClientHtml.addCustomCSS(html)
216 html = ClientHtml.addTitleTag(html) 230 html = ClientHtml.addTitleTag(html)
231 html = ClientHtml.addDescriptionTag(html)
232 html = ClientHtml.addServerConfig(html, serverConfig)
217 233
218 ClientHtml.htmlCache[path] = html 234 ClientHtml.htmlCache[path] = html
219 235
@@ -275,6 +291,7 @@ class ClientHtml {
275 if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path] 291 if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path]
276 292
277 const buffer = await readFile(path) 293 const buffer = await readFile(path)
294 const serverConfig = await ServerConfigManager.Instance.getHTMLServerConfig()
278 295
279 let html = buffer.toString() 296 let html = buffer.toString()
280 297
@@ -283,6 +300,7 @@ class ClientHtml {
283 html = ClientHtml.addFaviconContentHash(html) 300 html = ClientHtml.addFaviconContentHash(html)
284 html = ClientHtml.addLogoContentHash(html) 301 html = ClientHtml.addLogoContentHash(html)
285 html = ClientHtml.addCustomCSS(html) 302 html = ClientHtml.addCustomCSS(html)
303 html = ClientHtml.addServerConfig(html, serverConfig)
286 html = await ClientHtml.addAsyncPluginCSS(html) 304 html = await ClientHtml.addAsyncPluginCSS(html)
287 305
288 ClientHtml.htmlCache[path] = html 306 ClientHtml.htmlCache[path] = html
@@ -355,6 +373,13 @@ class ClientHtml {
355 return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.CUSTOM_CSS, styleTag) 373 return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.CUSTOM_CSS, styleTag)
356 } 374 }
357 375
376 private static addServerConfig (htmlStringPage: string, serverConfig: HTMLServerConfig) {
377 const serverConfigString = JSON.stringify(serverConfig)
378 const configScriptTag = `<script type="application/javascript">window.PeerTubeServerConfig = '${serverConfigString}'</script>`
379
380 return htmlStringPage.replace(CUSTOM_HTML_TAG_COMMENTS.SERVER_CONFIG, configScriptTag)
381 }
382
358 private static async addAsyncPluginCSS (htmlStringPage: string) { 383 private static async addAsyncPluginCSS (htmlStringPage: string) {
359 const globalCSSContent = await readFile(PLUGIN_GLOBAL_CSS_PATH) 384 const globalCSSContent = await readFile(PLUGIN_GLOBAL_CSS_PATH)
360 if (globalCSSContent.byteLength === 0) return htmlStringPage 385 if (globalCSSContent.byteLength === 0) return htmlStringPage
diff --git a/server/lib/config.ts b/server/lib/config.ts
deleted file mode 100644
index b4c4c9299..000000000
--- a/server/lib/config.ts
+++ /dev/null
@@ -1,255 +0,0 @@
1import { isSignupAllowed, isSignupAllowedForCurrentIP } from '@server/helpers/signup'
2import { getServerCommit } from '@server/helpers/utils'
3import { CONFIG, isEmailEnabled } from '@server/initializers/config'
4import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants'
5import { RegisteredExternalAuthConfig, RegisteredIdAndPassAuthConfig, ServerConfig } from '@shared/models'
6import { Hooks } from './plugins/hooks'
7import { PluginManager } from './plugins/plugin-manager'
8import { getThemeOrDefault } from './plugins/theme-utils'
9import { getEnabledResolutions } from './video-transcoding'
10import { VideoTranscodingProfilesManager } from './video-transcoding-profiles'
11
12let serverCommit: string
13
14async function getServerConfig (ip?: string): Promise<ServerConfig> {
15 if (serverCommit === undefined) serverCommit = await getServerCommit()
16
17 const { allowed } = await Hooks.wrapPromiseFun(
18 isSignupAllowed,
19 {
20 ip
21 },
22 'filter:api.user.signup.allowed.result'
23 )
24
25 const allowedForCurrentIP = isSignupAllowedForCurrentIP(ip)
26 const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME)
27
28 return {
29 instance: {
30 name: CONFIG.INSTANCE.NAME,
31 shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION,
32 isNSFW: CONFIG.INSTANCE.IS_NSFW,
33 defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
34 defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE,
35 customizations: {
36 javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT,
37 css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS
38 }
39 },
40 search: {
41 remoteUri: {
42 users: CONFIG.SEARCH.REMOTE_URI.USERS,
43 anonymous: CONFIG.SEARCH.REMOTE_URI.ANONYMOUS
44 },
45 searchIndex: {
46 enabled: CONFIG.SEARCH.SEARCH_INDEX.ENABLED,
47 url: CONFIG.SEARCH.SEARCH_INDEX.URL,
48 disableLocalSearch: CONFIG.SEARCH.SEARCH_INDEX.DISABLE_LOCAL_SEARCH,
49 isDefaultSearch: CONFIG.SEARCH.SEARCH_INDEX.IS_DEFAULT_SEARCH
50 }
51 },
52 plugin: {
53 registered: getRegisteredPlugins(),
54 registeredExternalAuths: getExternalAuthsPlugins(),
55 registeredIdAndPassAuths: getIdAndPassAuthPlugins()
56 },
57 theme: {
58 registered: getRegisteredThemes(),
59 default: defaultTheme
60 },
61 email: {
62 enabled: isEmailEnabled()
63 },
64 contactForm: {
65 enabled: CONFIG.CONTACT_FORM.ENABLED
66 },
67 serverVersion: PEERTUBE_VERSION,
68 serverCommit,
69 signup: {
70 allowed,
71 allowedForCurrentIP,
72 requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION
73 },
74 transcoding: {
75 hls: {
76 enabled: CONFIG.TRANSCODING.HLS.ENABLED
77 },
78 webtorrent: {
79 enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED
80 },
81 enabledResolutions: getEnabledResolutions('vod'),
82 profile: CONFIG.TRANSCODING.PROFILE,
83 availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('vod')
84 },
85 live: {
86 enabled: CONFIG.LIVE.ENABLED,
87
88 allowReplay: CONFIG.LIVE.ALLOW_REPLAY,
89 maxDuration: CONFIG.LIVE.MAX_DURATION,
90 maxInstanceLives: CONFIG.LIVE.MAX_INSTANCE_LIVES,
91 maxUserLives: CONFIG.LIVE.MAX_USER_LIVES,
92
93 transcoding: {
94 enabled: CONFIG.LIVE.TRANSCODING.ENABLED,
95 enabledResolutions: getEnabledResolutions('live'),
96 profile: CONFIG.LIVE.TRANSCODING.PROFILE,
97 availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('live')
98 },
99
100 rtmp: {
101 port: CONFIG.LIVE.RTMP.PORT
102 }
103 },
104 import: {
105 videos: {
106 http: {
107 enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED
108 },
109 torrent: {
110 enabled: CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED
111 }
112 }
113 },
114 autoBlacklist: {
115 videos: {
116 ofUsers: {
117 enabled: CONFIG.AUTO_BLACKLIST.VIDEOS.OF_USERS.ENABLED
118 }
119 }
120 },
121 avatar: {
122 file: {
123 size: {
124 max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
125 },
126 extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
127 }
128 },
129 banner: {
130 file: {
131 size: {
132 max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
133 },
134 extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
135 }
136 },
137 video: {
138 image: {
139 extensions: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME,
140 size: {
141 max: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max
142 }
143 },
144 file: {
145 extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME
146 }
147 },
148 videoCaption: {
149 file: {
150 size: {
151 max: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE.max
152 },
153 extensions: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.EXTNAME
154 }
155 },
156 user: {
157 videoQuota: CONFIG.USER.VIDEO_QUOTA,
158 videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY
159 },
160 trending: {
161 videos: {
162 intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS,
163 algorithms: {
164 enabled: CONFIG.TRENDING.VIDEOS.ALGORITHMS.ENABLED,
165 default: CONFIG.TRENDING.VIDEOS.ALGORITHMS.DEFAULT
166 }
167 }
168 },
169 tracker: {
170 enabled: CONFIG.TRACKER.ENABLED
171 },
172
173 followings: {
174 instance: {
175 autoFollowIndex: {
176 indexUrl: CONFIG.FOLLOWINGS.INSTANCE.AUTO_FOLLOW_INDEX.INDEX_URL
177 }
178 }
179 },
180
181 broadcastMessage: {
182 enabled: CONFIG.BROADCAST_MESSAGE.ENABLED,
183 message: CONFIG.BROADCAST_MESSAGE.MESSAGE,
184 level: CONFIG.BROADCAST_MESSAGE.LEVEL,
185 dismissable: CONFIG.BROADCAST_MESSAGE.DISMISSABLE
186 }
187 }
188}
189
190function getRegisteredThemes () {
191 return PluginManager.Instance.getRegisteredThemes()
192 .map(t => ({
193 name: t.name,
194 version: t.version,
195 description: t.description,
196 css: t.css,
197 clientScripts: t.clientScripts
198 }))
199}
200
201function getRegisteredPlugins () {
202 return PluginManager.Instance.getRegisteredPlugins()
203 .map(p => ({
204 name: p.name,
205 version: p.version,
206 description: p.description,
207 clientScripts: p.clientScripts
208 }))
209}
210
211// ---------------------------------------------------------------------------
212
213export {
214 getServerConfig,
215 getRegisteredThemes,
216 getRegisteredPlugins
217}
218
219// ---------------------------------------------------------------------------
220
221function getIdAndPassAuthPlugins () {
222 const result: RegisteredIdAndPassAuthConfig[] = []
223
224 for (const p of PluginManager.Instance.getIdAndPassAuths()) {
225 for (const auth of p.idAndPassAuths) {
226 result.push({
227 npmName: p.npmName,
228 name: p.name,
229 version: p.version,
230 authName: auth.authName,
231 weight: auth.getWeight()
232 })
233 }
234 }
235
236 return result
237}
238
239function getExternalAuthsPlugins () {
240 const result: RegisteredExternalAuthConfig[] = []
241
242 for (const p of PluginManager.Instance.getExternalAuths()) {
243 for (const auth of p.externalAuths) {
244 result.push({
245 npmName: p.npmName,
246 name: p.name,
247 version: p.version,
248 authName: auth.authName,
249 authDisplayName: auth.authDisplayName()
250 })
251 }
252 }
253
254 return result
255}
diff --git a/server/lib/job-queue/handlers/activitypub-follow.ts b/server/lib/job-queue/handlers/activitypub-follow.ts
index 82c95be80..ec8df8969 100644
--- a/server/lib/job-queue/handlers/activitypub-follow.ts
+++ b/server/lib/job-queue/handlers/activitypub-follow.ts
@@ -1,18 +1,18 @@
1import * as Bull from 'bull' 1import * as Bull from 'bull'
2import { logger } from '../../../helpers/logger' 2import { getLocalActorFollowActivityPubUrl } from '@server/lib/activitypub/url'
3import { REMOTE_SCHEME, WEBSERVER } from '../../../initializers/constants' 3import { ActivitypubFollowPayload } from '@shared/models'
4import { sendFollow } from '../../activitypub/send'
5import { sanitizeHost } from '../../../helpers/core-utils' 4import { sanitizeHost } from '../../../helpers/core-utils'
6import { loadActorUrlOrGetFromWebfinger } from '../../../helpers/webfinger'
7import { getOrCreateActorAndServerAndModel } from '../../activitypub/actor'
8import { retryTransactionWrapper } from '../../../helpers/database-utils' 5import { retryTransactionWrapper } from '../../../helpers/database-utils'
9import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 6import { logger } from '../../../helpers/logger'
10import { ActorModel } from '../../../models/activitypub/actor' 7import { loadActorUrlOrGetFromWebfinger } from '../../../helpers/webfinger'
11import { Notifier } from '../../notifier' 8import { REMOTE_SCHEME, WEBSERVER } from '../../../initializers/constants'
12import { sequelizeTypescript } from '../../../initializers/database' 9import { sequelizeTypescript } from '../../../initializers/database'
10import { ActorModel } from '../../../models/actor/actor'
11import { ActorFollowModel } from '../../../models/actor/actor-follow'
13import { MActor, MActorFollowActors, MActorFull } from '../../../types/models' 12import { MActor, MActorFollowActors, MActorFull } from '../../../types/models'
14import { ActivitypubFollowPayload } from '@shared/models' 13import { getOrCreateActorAndServerAndModel } from '../../activitypub/actor'
15import { getLocalActorFollowActivityPubUrl } from '@server/lib/activitypub/url' 14import { sendFollow } from '../../activitypub/send'
15import { Notifier } from '../../notifier'
16 16
17async function processActivityPubFollow (job: Bull.Job) { 17async function processActivityPubFollow (job: Bull.Job) {
18 const payload = job.data as ActivitypubFollowPayload 18 const payload = job.data as ActivitypubFollowPayload
diff --git a/server/lib/job-queue/handlers/activitypub-refresher.ts b/server/lib/job-queue/handlers/activitypub-refresher.ts
index 666e56868..c09b1bcc8 100644
--- a/server/lib/job-queue/handlers/activitypub-refresher.ts
+++ b/server/lib/job-queue/handlers/activitypub-refresher.ts
@@ -1,12 +1,12 @@
1import * as Bull from 'bull' 1import * as Bull from 'bull'
2import { refreshVideoPlaylistIfNeeded } from '@server/lib/activitypub/playlist'
3import { RefreshPayload } from '@shared/models'
2import { logger } from '../../../helpers/logger' 4import { logger } from '../../../helpers/logger'
3import { fetchVideoByUrl } from '../../../helpers/video' 5import { fetchVideoByUrl } from '../../../helpers/video'
6import { ActorModel } from '../../../models/actor/actor'
7import { VideoPlaylistModel } from '../../../models/video/video-playlist'
4import { refreshActorIfNeeded } from '../../activitypub/actor' 8import { refreshActorIfNeeded } from '../../activitypub/actor'
5import { refreshVideoIfNeeded } from '../../activitypub/videos' 9import { refreshVideoIfNeeded } from '../../activitypub/videos'
6import { ActorModel } from '../../../models/activitypub/actor'
7import { VideoPlaylistModel } from '../../../models/video/video-playlist'
8import { RefreshPayload } from '@shared/models'
9import { refreshVideoPlaylistIfNeeded } from '@server/lib/activitypub/playlist'
10 10
11async function refreshAPObject (job: Bull.Job) { 11async function refreshAPObject (job: Bull.Job) {
12 const payload = job.data as RefreshPayload 12 const payload = job.data as RefreshPayload
diff --git a/server/lib/job-queue/handlers/actor-keys.ts b/server/lib/job-queue/handlers/actor-keys.ts
index 125307843..3eef565d0 100644
--- a/server/lib/job-queue/handlers/actor-keys.ts
+++ b/server/lib/job-queue/handlers/actor-keys.ts
@@ -1,6 +1,6 @@
1import * as Bull from 'bull' 1import * as Bull from 'bull'
2import { generateAndSaveActorKeys } from '@server/lib/activitypub/actor' 2import { generateAndSaveActorKeys } from '@server/lib/activitypub/actor'
3import { ActorModel } from '@server/models/activitypub/actor' 3import { ActorModel } from '@server/models/actor/actor'
4import { ActorKeysPayload } from '@shared/models' 4import { ActorKeysPayload } from '@shared/models'
5import { logger } from '../../../helpers/logger' 5import { logger } from '../../../helpers/logger'
6 6
diff --git a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts
index e8a91450d..37e7c1fad 100644
--- a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts
+++ b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts
@@ -1,10 +1,10 @@
1import { buildDigest } from '@server/helpers/peertube-crypto'
2import { getServerActor } from '@server/models/application/application'
3import { ContextType } from '@shared/models/activitypub/context'
1import { buildSignedActivity } from '../../../../helpers/activitypub' 4import { buildSignedActivity } from '../../../../helpers/activitypub'
2import { ActorModel } from '../../../../models/activitypub/actor'
3import { ACTIVITY_PUB, HTTP_SIGNATURE } from '../../../../initializers/constants' 5import { ACTIVITY_PUB, HTTP_SIGNATURE } from '../../../../initializers/constants'
6import { ActorModel } from '../../../../models/actor/actor'
4import { MActor } from '../../../../types/models' 7import { MActor } from '../../../../types/models'
5import { getServerActor } from '@server/models/application/application'
6import { buildDigest } from '@server/helpers/peertube-crypto'
7import { ContextType } from '@shared/models/activitypub/context'
8 8
9type Payload <T> = { body: T, contextType?: ContextType, signatureActorId?: number } 9type Payload <T> = { body: T, contextType?: ContextType, signatureActorId?: number }
10 10
diff --git a/server/lib/job-queue/handlers/video-file-import.ts b/server/lib/job-queue/handlers/video-file-import.ts
index 71f2cafcd..8297a1571 100644
--- a/server/lib/job-queue/handlers/video-file-import.ts
+++ b/server/lib/job-queue/handlers/video-file-import.ts
@@ -3,7 +3,7 @@ import { copy, stat } from 'fs-extra'
3import { extname } from 'path' 3import { extname } from 'path'
4import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' 4import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent'
5import { generateVideoFilename, getVideoFilePath } from '@server/lib/video-paths' 5import { generateVideoFilename, getVideoFilePath } from '@server/lib/video-paths'
6import { UserModel } from '@server/models/account/user' 6import { UserModel } from '@server/models/user/user'
7import { MVideoFullLight } from '@server/types/models' 7import { MVideoFullLight } from '@server/types/models'
8import { VideoFileImportPayload } from '@shared/models' 8import { VideoFileImportPayload } from '@shared/models'
9import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffprobe-utils' 9import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffprobe-utils'
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts
index ed2c5eac0..d71053e87 100644
--- a/server/lib/job-queue/handlers/video-import.ts
+++ b/server/lib/job-queue/handlers/video-import.ts
@@ -2,8 +2,10 @@ import * as Bull from 'bull'
2import { move, remove, stat } from 'fs-extra' 2import { move, remove, stat } from 'fs-extra'
3import { extname } from 'path' 3import { extname } from 'path'
4import { retryTransactionWrapper } from '@server/helpers/database-utils' 4import { retryTransactionWrapper } from '@server/helpers/database-utils'
5import { YoutubeDL } from '@server/helpers/youtube-dl'
5import { isPostImportVideoAccepted } from '@server/lib/moderation' 6import { isPostImportVideoAccepted } from '@server/lib/moderation'
6import { Hooks } from '@server/lib/plugins/hooks' 7import { Hooks } from '@server/lib/plugins/hooks'
8import { ServerConfigManager } from '@server/lib/server-config-manager'
7import { isAbleToUploadVideo } from '@server/lib/user' 9import { isAbleToUploadVideo } from '@server/lib/user'
8import { addOptimizeOrMergeAudioJob } from '@server/lib/video' 10import { addOptimizeOrMergeAudioJob } from '@server/lib/video'
9import { generateVideoFilename, getVideoFilePath } from '@server/lib/video-paths' 11import { generateVideoFilename, getVideoFilePath } from '@server/lib/video-paths'
@@ -23,7 +25,6 @@ import { getDurationFromVideoFile, getVideoFileFPS, getVideoFileResolution } fro
23import { logger } from '../../../helpers/logger' 25import { logger } from '../../../helpers/logger'
24import { getSecureTorrentName } from '../../../helpers/utils' 26import { getSecureTorrentName } from '../../../helpers/utils'
25import { createTorrentAndSetInfoHash, downloadWebTorrentVideo } from '../../../helpers/webtorrent' 27import { createTorrentAndSetInfoHash, downloadWebTorrentVideo } from '../../../helpers/webtorrent'
26import { downloadYoutubeDLVideo } from '../../../helpers/youtube-dl'
27import { CONFIG } from '../../../initializers/config' 28import { CONFIG } from '../../../initializers/config'
28import { VIDEO_IMPORT_TIMEOUT } from '../../../initializers/constants' 29import { VIDEO_IMPORT_TIMEOUT } from '../../../initializers/constants'
29import { sequelizeTypescript } from '../../../initializers/database' 30import { sequelizeTypescript } from '../../../initializers/database'
@@ -75,8 +76,10 @@ async function processYoutubeDLImport (job: Bull.Job, payload: VideoImportYoutub
75 videoImportId: videoImport.id 76 videoImportId: videoImport.id
76 } 77 }
77 78
79 const youtubeDL = new YoutubeDL(videoImport.targetUrl, ServerConfigManager.Instance.getEnabledResolutions('vod'))
80
78 return processFile( 81 return processFile(
79 () => downloadYoutubeDLVideo(videoImport.targetUrl, payload.fileExt, VIDEO_IMPORT_TIMEOUT), 82 () => youtubeDL.downloadYoutubeDLVideo(payload.fileExt, VIDEO_IMPORT_TIMEOUT),
80 videoImport, 83 videoImport,
81 options 84 options
82 ) 85 )
diff --git a/server/lib/job-queue/handlers/video-live-ending.ts b/server/lib/job-queue/handlers/video-live-ending.ts
index d57202ca5..517b90abc 100644
--- a/server/lib/job-queue/handlers/video-live-ending.ts
+++ b/server/lib/job-queue/handlers/video-live-ending.ts
@@ -5,9 +5,9 @@ import { ffprobePromise, getAudioStream, getDurationFromVideoFile, getVideoFileR
5import { VIDEO_LIVE } from '@server/initializers/constants' 5import { VIDEO_LIVE } from '@server/initializers/constants'
6import { LiveManager } from '@server/lib/live-manager' 6import { LiveManager } from '@server/lib/live-manager'
7import { generateVideoMiniature } from '@server/lib/thumbnail' 7import { generateVideoMiniature } from '@server/lib/thumbnail'
8import { generateHlsPlaylistResolutionFromTS } from '@server/lib/transcoding/video-transcoding'
8import { publishAndFederateIfNeeded } from '@server/lib/video' 9import { publishAndFederateIfNeeded } from '@server/lib/video'
9import { getHLSDirectory } from '@server/lib/video-paths' 10import { getHLSDirectory } from '@server/lib/video-paths'
10import { generateHlsPlaylistResolutionFromTS } from '@server/lib/video-transcoding'
11import { VideoModel } from '@server/models/video/video' 11import { VideoModel } from '@server/models/video/video'
12import { VideoFileModel } from '@server/models/video/video-file' 12import { VideoFileModel } from '@server/models/video/video-file'
13import { VideoLiveModel } from '@server/models/video/video-live' 13import { VideoLiveModel } from '@server/models/video/video-live'
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts
index 010b95b05..8d659daa6 100644
--- a/server/lib/job-queue/handlers/video-transcoding.ts
+++ b/server/lib/job-queue/handlers/video-transcoding.ts
@@ -2,7 +2,7 @@ import * as Bull from 'bull'
2import { TranscodeOptionsType } from '@server/helpers/ffmpeg-utils' 2import { TranscodeOptionsType } from '@server/helpers/ffmpeg-utils'
3import { getTranscodingJobPriority, publishAndFederateIfNeeded } from '@server/lib/video' 3import { getTranscodingJobPriority, publishAndFederateIfNeeded } from '@server/lib/video'
4import { getVideoFilePath } from '@server/lib/video-paths' 4import { getVideoFilePath } from '@server/lib/video-paths'
5import { UserModel } from '@server/models/account/user' 5import { UserModel } from '@server/models/user/user'
6import { MUser, MUserId, MVideoFullLight, MVideoUUID, MVideoWithFile } from '@server/types/models' 6import { MUser, MUserId, MVideoFullLight, MVideoUUID, MVideoWithFile } from '@server/types/models'
7import { 7import {
8 HLSTranscodingPayload, 8 HLSTranscodingPayload,
@@ -24,7 +24,7 @@ import {
24 mergeAudioVideofile, 24 mergeAudioVideofile,
25 optimizeOriginalVideofile, 25 optimizeOriginalVideofile,
26 transcodeNewWebTorrentResolution 26 transcodeNewWebTorrentResolution
27} from '../../video-transcoding' 27} from '../../transcoding/video-transcoding'
28import { JobQueue } from '../job-queue' 28import { JobQueue } from '../job-queue'
29 29
30type HandlerFunction = (job: Bull.Job, payload: VideoTranscodingPayload, video: MVideoFullLight, user: MUser) => Promise<any> 30type HandlerFunction = (job: Bull.Job, payload: VideoTranscodingPayload, video: MVideoFullLight, user: MUser) => Promise<any>
diff --git a/server/lib/job-queue/handlers/video-views.ts b/server/lib/job-queue/handlers/video-views.ts
index 897235ec0..86d0a271f 100644
--- a/server/lib/job-queue/handlers/video-views.ts
+++ b/server/lib/job-queue/handlers/video-views.ts
@@ -36,8 +36,8 @@ async function processVideosViews () {
36 } 36 }
37 37
38 await VideoViewModel.create({ 38 await VideoViewModel.create({
39 startDate, 39 startDate: new Date(startDate),
40 endDate, 40 endDate: new Date(endDate),
41 views, 41 views,
42 videoId 42 videoId
43 }) 43 })
diff --git a/server/lib/live-manager.ts b/server/lib/live-manager.ts
index 66b5d119b..563ba2578 100644
--- a/server/lib/live-manager.ts
+++ b/server/lib/live-manager.ts
@@ -8,10 +8,10 @@ import { basename, join } from 'path'
8import { isTestInstance } from '@server/helpers/core-utils' 8import { isTestInstance } from '@server/helpers/core-utils'
9import { getLiveMuxingCommand, getLiveTranscodingCommand } from '@server/helpers/ffmpeg-utils' 9import { getLiveMuxingCommand, getLiveTranscodingCommand } from '@server/helpers/ffmpeg-utils'
10import { computeResolutionsToTranscode, getVideoFileFPS, getVideoFileResolution } from '@server/helpers/ffprobe-utils' 10import { computeResolutionsToTranscode, getVideoFileFPS, getVideoFileResolution } from '@server/helpers/ffprobe-utils'
11import { logger } from '@server/helpers/logger' 11import { logger, loggerTagsFactory } from '@server/helpers/logger'
12import { CONFIG, registerConfigChangedHandler } from '@server/initializers/config' 12import { CONFIG, registerConfigChangedHandler } from '@server/initializers/config'
13import { MEMOIZE_TTL, P2P_MEDIA_LOADER_PEER_VERSION, VIDEO_LIVE, VIEW_LIFETIME, WEBSERVER } from '@server/initializers/constants' 13import { MEMOIZE_TTL, P2P_MEDIA_LOADER_PEER_VERSION, VIDEO_LIVE, VIEW_LIFETIME, WEBSERVER } from '@server/initializers/constants'
14import { UserModel } from '@server/models/account/user' 14import { UserModel } from '@server/models/user/user'
15import { VideoModel } from '@server/models/video/video' 15import { VideoModel } from '@server/models/video/video'
16import { VideoFileModel } from '@server/models/video/video-file' 16import { VideoFileModel } from '@server/models/video/video-file'
17import { VideoLiveModel } from '@server/models/video/video-live' 17import { VideoLiveModel } from '@server/models/video/video-live'
@@ -23,9 +23,9 @@ import { buildSha256Segment } from './hls'
23import { JobQueue } from './job-queue' 23import { JobQueue } from './job-queue'
24import { cleanupLive } from './job-queue/handlers/video-live-ending' 24import { cleanupLive } from './job-queue/handlers/video-live-ending'
25import { PeerTubeSocket } from './peertube-socket' 25import { PeerTubeSocket } from './peertube-socket'
26import { VideoTranscodingProfilesManager } from './transcoding/video-transcoding-profiles'
26import { isAbleToUploadVideo } from './user' 27import { isAbleToUploadVideo } from './user'
27import { getHLSDirectory } from './video-paths' 28import { getHLSDirectory } from './video-paths'
28import { VideoTranscodingProfilesManager } from './video-transcoding-profiles'
29 29
30import memoizee = require('memoizee') 30import memoizee = require('memoizee')
31const NodeRtmpSession = require('node-media-server/node_rtmp_session') 31const NodeRtmpSession = require('node-media-server/node_rtmp_session')
@@ -48,6 +48,8 @@ const config = {
48 } 48 }
49} 49}
50 50
51const lTags = loggerTagsFactory('live')
52
51class LiveManager { 53class LiveManager {
52 54
53 private static instance: LiveManager 55 private static instance: LiveManager
@@ -75,20 +77,20 @@ class LiveManager {
75 init () { 77 init () {
76 const events = this.getContext().nodeEvent 78 const events = this.getContext().nodeEvent
77 events.on('postPublish', (sessionId: string, streamPath: string) => { 79 events.on('postPublish', (sessionId: string, streamPath: string) => {
78 logger.debug('RTMP received stream', { id: sessionId, streamPath }) 80 logger.debug('RTMP received stream', { id: sessionId, streamPath, ...lTags(sessionId) })
79 81
80 const splittedPath = streamPath.split('/') 82 const splittedPath = streamPath.split('/')
81 if (splittedPath.length !== 3 || splittedPath[1] !== VIDEO_LIVE.RTMP.BASE_PATH) { 83 if (splittedPath.length !== 3 || splittedPath[1] !== VIDEO_LIVE.RTMP.BASE_PATH) {
82 logger.warn('Live path is incorrect.', { streamPath }) 84 logger.warn('Live path is incorrect.', { streamPath, ...lTags(sessionId) })
83 return this.abortSession(sessionId) 85 return this.abortSession(sessionId)
84 } 86 }
85 87
86 this.handleSession(sessionId, streamPath, splittedPath[2]) 88 this.handleSession(sessionId, streamPath, splittedPath[2])
87 .catch(err => logger.error('Cannot handle sessions.', { err })) 89 .catch(err => logger.error('Cannot handle sessions.', { err, ...lTags(sessionId) }))
88 }) 90 })
89 91
90 events.on('donePublish', sessionId => { 92 events.on('donePublish', sessionId => {
91 logger.info('Live session ended.', { sessionId }) 93 logger.info('Live session ended.', { sessionId, ...lTags(sessionId) })
92 }) 94 })
93 95
94 registerConfigChangedHandler(() => { 96 registerConfigChangedHandler(() => {
@@ -104,13 +106,13 @@ class LiveManager {
104 106
105 // Cleanup broken lives, that were terminated by a server restart for example 107 // Cleanup broken lives, that were terminated by a server restart for example
106 this.handleBrokenLives() 108 this.handleBrokenLives()
107 .catch(err => logger.error('Cannot handle broken lives.', { err })) 109 .catch(err => logger.error('Cannot handle broken lives.', { err, ...lTags() }))
108 110
109 setInterval(() => this.updateLiveViews(), VIEW_LIFETIME.LIVE) 111 setInterval(() => this.updateLiveViews(), VIEW_LIFETIME.LIVE)
110 } 112 }
111 113
112 run () { 114 run () {
113 logger.info('Running RTMP server on port %d', config.rtmp.port) 115 logger.info('Running RTMP server on port %d', config.rtmp.port, lTags())
114 116
115 this.rtmpServer = createServer(socket => { 117 this.rtmpServer = createServer(socket => {
116 const session = new NodeRtmpSession(config, socket) 118 const session = new NodeRtmpSession(config, socket)
@@ -119,14 +121,14 @@ class LiveManager {
119 }) 121 })
120 122
121 this.rtmpServer.on('error', err => { 123 this.rtmpServer.on('error', err => {
122 logger.error('Cannot run RTMP server.', { err }) 124 logger.error('Cannot run RTMP server.', { err, ...lTags() })
123 }) 125 })
124 126
125 this.rtmpServer.listen(CONFIG.LIVE.RTMP.PORT) 127 this.rtmpServer.listen(CONFIG.LIVE.RTMP.PORT)
126 } 128 }
127 129
128 stop () { 130 stop () {
129 logger.info('Stopping RTMP server.') 131 logger.info('Stopping RTMP server.', lTags())
130 132
131 this.rtmpServer.close() 133 this.rtmpServer.close()
132 this.rtmpServer = undefined 134 this.rtmpServer = undefined
@@ -185,7 +187,7 @@ class LiveManager {
185 187
186 return readFile(segmentPath) 188 return readFile(segmentPath)
187 .then(data => appendFile(dest, data)) 189 .then(data => appendFile(dest, data))
188 .catch(err => logger.error('Cannot copy segment %s to repay directory.', segmentPath, { err })) 190 .catch(err => logger.error('Cannot copy segment %s to replay directory.', segmentPath, { err, ...lTags() }))
189 } 191 }
190 192
191 buildConcatenatedName (segmentOrPlaylistPath: string) { 193 buildConcatenatedName (segmentOrPlaylistPath: string) {
@@ -202,7 +204,7 @@ class LiveManager {
202 if (videoLive.saveReplay) { 204 if (videoLive.saveReplay) {
203 await this.addSegmentToReplay(hlsVideoPath, previousSegment) 205 await this.addSegmentToReplay(hlsVideoPath, previousSegment)
204 } 206 }
205 }).catch(err => logger.error('Cannot process segments in %s', hlsVideoPath, { err })) 207 }).catch(err => logger.error('Cannot process segments in %s', hlsVideoPath, { err, ...lTags(videoUUID) }))
206 } 208 }
207 209
208 private getContext () { 210 private getContext () {
@@ -226,13 +228,13 @@ class LiveManager {
226 private async handleSession (sessionId: string, streamPath: string, streamKey: string) { 228 private async handleSession (sessionId: string, streamPath: string, streamKey: string) {
227 const videoLive = await VideoLiveModel.loadByStreamKey(streamKey) 229 const videoLive = await VideoLiveModel.loadByStreamKey(streamKey)
228 if (!videoLive) { 230 if (!videoLive) {
229 logger.warn('Unknown live video with stream key %s.', streamKey) 231 logger.warn('Unknown live video with stream key %s.', streamKey, lTags(sessionId))
230 return this.abortSession(sessionId) 232 return this.abortSession(sessionId)
231 } 233 }
232 234
233 const video = videoLive.Video 235 const video = videoLive.Video
234 if (video.isBlacklisted()) { 236 if (video.isBlacklisted()) {
235 logger.warn('Video is blacklisted. Refusing stream %s.', streamKey) 237 logger.warn('Video is blacklisted. Refusing stream %s.', streamKey, lTags(sessionId, video.uuid))
236 return this.abortSession(sessionId) 238 return this.abortSession(sessionId)
237 } 239 }
238 240
@@ -262,7 +264,10 @@ class LiveManager {
262 264
263 const allResolutions = resolutionsEnabled.concat([ session.videoHeight ]) 265 const allResolutions = resolutionsEnabled.concat([ session.videoHeight ])
264 266
265 logger.info('Will mux/transcode live video of original resolution %d.', session.videoHeight, { allResolutions }) 267 logger.info(
268 'Will mux/transcode live video of original resolution %d.', session.videoHeight,
269 { allResolutions, ...lTags(sessionId, video.uuid) }
270 )
266 271
267 const [ videoStreamingPlaylist ] = await VideoStreamingPlaylistModel.upsert({ 272 const [ videoStreamingPlaylist ] = await VideoStreamingPlaylistModel.upsert({
268 videoId: video.id, 273 videoId: video.id,
@@ -317,7 +322,7 @@ class LiveManager {
317 }) 322 })
318 323
319 VideoFileModel.customUpsert(file, 'streaming-playlist', null) 324 VideoFileModel.customUpsert(file, 'streaming-playlist', null)
320 .catch(err => logger.error('Cannot create file for live streaming.', { err })) 325 .catch(err => logger.error('Cannot create file for live streaming.', { err, ...lTags(sessionId, videoLive.Video.uuid) }))
321 } 326 }
322 327
323 const outPath = getHLSDirectory(videoLive.Video) 328 const outPath = getHLSDirectory(videoLive.Video)
@@ -342,7 +347,7 @@ class LiveManager {
342 }) 347 })
343 : getLiveMuxingCommand(rtmpUrl, outPath) 348 : getLiveMuxingCommand(rtmpUrl, outPath)
344 349
345 logger.info('Running live muxing/transcoding for %s.', videoUUID) 350 logger.info('Running live muxing/transcoding for %s.', videoUUID, lTags(sessionId, videoUUID))
346 this.transSessions.set(sessionId, ffmpegExec) 351 this.transSessions.set(sessionId, ffmpegExec)
347 352
348 const tsWatcher = chokidar.watch(outPath + '/*.ts') 353 const tsWatcher = chokidar.watch(outPath + '/*.ts')
@@ -351,7 +356,7 @@ class LiveManager {
351 const playlistIdMatcher = /^([\d+])-/ 356 const playlistIdMatcher = /^([\d+])-/
352 357
353 const addHandler = segmentPath => { 358 const addHandler = segmentPath => {
354 logger.debug('Live add handler of %s.', segmentPath) 359 logger.debug('Live add handler of %s.', segmentPath, lTags(sessionId, videoUUID))
355 360
356 const playlistId = basename(segmentPath).match(playlistIdMatcher)[0] 361 const playlistId = basename(segmentPath).match(playlistIdMatcher)[0]
357 362
@@ -363,7 +368,9 @@ class LiveManager {
363 if (this.hasClientSocketsInBadHealthWithCache(sessionId)) { 368 if (this.hasClientSocketsInBadHealthWithCache(sessionId)) {
364 logger.error( 369 logger.error(
365 'Too much data in client socket stream (ffmpeg is too slow to transcode the video).' + 370 'Too much data in client socket stream (ffmpeg is too slow to transcode the video).' +
366 ' Stopping session of video %s.', videoUUID) 371 ' Stopping session of video %s.', videoUUID,
372 lTags(sessionId, videoUUID)
373 )
367 374
368 this.stopSessionOf(videoLive.videoId) 375 this.stopSessionOf(videoLive.videoId)
369 return 376 return
@@ -371,7 +378,7 @@ class LiveManager {
371 378
372 // Duration constraint check 379 // Duration constraint check
373 if (this.isDurationConstraintValid(startStreamDateTime) !== true) { 380 if (this.isDurationConstraintValid(startStreamDateTime) !== true) {
374 logger.info('Stopping session of %s: max duration exceeded.', videoUUID) 381 logger.info('Stopping session of %s: max duration exceeded.', videoUUID, lTags(sessionId, videoUUID))
375 382
376 this.stopSessionOf(videoLive.videoId) 383 this.stopSessionOf(videoLive.videoId)
377 return 384 return
@@ -386,12 +393,12 @@ class LiveManager {
386 .then(() => this.isQuotaConstraintValid(user, videoLive)) 393 .then(() => this.isQuotaConstraintValid(user, videoLive))
387 .then(quotaValid => { 394 .then(quotaValid => {
388 if (quotaValid !== true) { 395 if (quotaValid !== true) {
389 logger.info('Stopping session of %s: user quota exceeded.', videoUUID) 396 logger.info('Stopping session of %s: user quota exceeded.', videoUUID, lTags(sessionId, videoUUID))
390 397
391 this.stopSessionOf(videoLive.videoId) 398 this.stopSessionOf(videoLive.videoId)
392 } 399 }
393 }) 400 })
394 .catch(err => logger.error('Cannot stat %s or check quota of %d.', segmentPath, user.id, { err })) 401 .catch(err => logger.error('Cannot stat %s or check quota of %d.', segmentPath, user.id, { err, ...lTags(sessionId, videoUUID) }))
395 } 402 }
396 } 403 }
397 404
@@ -411,21 +418,21 @@ class LiveManager {
411 418
412 setTimeout(() => { 419 setTimeout(() => {
413 federateVideoIfNeeded(video, false) 420 federateVideoIfNeeded(video, false)
414 .catch(err => logger.error('Cannot federate live video %s.', video.url, { err })) 421 .catch(err => logger.error('Cannot federate live video %s.', video.url, { err, ...lTags(sessionId, videoUUID) }))
415 422
416 PeerTubeSocket.Instance.sendVideoLiveNewState(video) 423 PeerTubeSocket.Instance.sendVideoLiveNewState(video)
417 }, VIDEO_LIVE.SEGMENT_TIME_SECONDS * 1000 * VIDEO_LIVE.EDGE_LIVE_DELAY_SEGMENTS_NOTIFICATION) 424 }, VIDEO_LIVE.SEGMENT_TIME_SECONDS * 1000 * VIDEO_LIVE.EDGE_LIVE_DELAY_SEGMENTS_NOTIFICATION)
418 425
419 } catch (err) { 426 } catch (err) {
420 logger.error('Cannot save/federate live video %d.', videoLive.videoId, { err }) 427 logger.error('Cannot save/federate live video %d.', videoLive.videoId, { err, ...lTags(sessionId, videoUUID) })
421 } finally { 428 } finally {
422 masterWatcher.close() 429 masterWatcher.close()
423 .catch(err => logger.error('Cannot close master watcher of %s.', outPath, { err })) 430 .catch(err => logger.error('Cannot close master watcher of %s.', outPath, { err, ...lTags(sessionId, videoUUID) }))
424 } 431 }
425 }) 432 })
426 433
427 const onFFmpegEnded = () => { 434 const onFFmpegEnded = () => {
428 logger.info('RTMP transmuxing for video %s ended. Scheduling cleanup', rtmpUrl) 435 logger.info('RTMP transmuxing for video %s ended. Scheduling cleanup', rtmpUrl, lTags(sessionId, videoUUID))
429 436
430 this.transSessions.delete(sessionId) 437 this.transSessions.delete(sessionId)
431 438
@@ -446,10 +453,15 @@ class LiveManager {
446 this.processSegments(outPath, videoUUID, videoLive, segmentsToProcessPerPlaylist[key]) 453 this.processSegments(outPath, videoUUID, videoLive, segmentsToProcessPerPlaylist[key])
447 } 454 }
448 }) 455 })
449 .catch(err => logger.error('Cannot close watchers of %s or process remaining hash segments.', outPath, { err })) 456 .catch(err => {
457 logger.error(
458 'Cannot close watchers of %s or process remaining hash segments.', outPath,
459 { err, ...lTags(sessionId, videoUUID) }
460 )
461 })
450 462
451 this.onEndTransmuxing(videoLive.Video.id) 463 this.onEndTransmuxing(videoLive.Video.id)
452 .catch(err => logger.error('Error in closed transmuxing.', { err })) 464 .catch(err => logger.error('Error in closed transmuxing.', { err, ...lTags(sessionId, videoUUID) }))
453 }, 1000) 465 }, 1000)
454 } 466 }
455 467
@@ -459,7 +471,7 @@ class LiveManager {
459 // Don't care that we killed the ffmpeg process 471 // Don't care that we killed the ffmpeg process
460 if (err?.message?.includes('Exiting normally')) return 472 if (err?.message?.includes('Exiting normally')) return
461 473
462 logger.error('Live transcoding error.', { err, stdout, stderr }) 474 logger.error('Live transcoding error.', { err, stdout, stderr, ...lTags(sessionId, videoUUID) })
463 475
464 this.abortSession(sessionId) 476 this.abortSession(sessionId)
465 }) 477 })
@@ -469,12 +481,12 @@ class LiveManager {
469 ffmpegExec.run() 481 ffmpegExec.run()
470 } 482 }
471 483
472 private async onEndTransmuxing (videoId: number, cleanupNow = false) { 484 private async onEndTransmuxing (videoUUID: string, cleanupNow = false) {
473 try { 485 try {
474 const fullVideo = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoId) 486 const fullVideo = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoUUID)
475 if (!fullVideo) return 487 if (!fullVideo) return
476 488
477 const live = await VideoLiveModel.loadByVideoId(videoId) 489 const live = await VideoLiveModel.loadByVideoId(fullVideo.id)
478 490
479 if (!live.permanentLive) { 491 if (!live.permanentLive) {
480 JobQueue.Instance.createJob({ 492 JobQueue.Instance.createJob({
@@ -495,13 +507,13 @@ class LiveManager {
495 507
496 await federateVideoIfNeeded(fullVideo, false) 508 await federateVideoIfNeeded(fullVideo, false)
497 } catch (err) { 509 } catch (err) {
498 logger.error('Cannot save/federate new video state of live streaming of video id %d.', videoId, { err }) 510 logger.error('Cannot save/federate new video state of live streaming of video %d.', videoUUID, { err, ...lTags(videoUUID) })
499 } 511 }
500 } 512 }
501 513
502 private async addSegmentSha (videoUUID: string, segmentPath: string) { 514 private async addSegmentSha (videoUUID: string, segmentPath: string) {
503 const segmentName = basename(segmentPath) 515 const segmentName = basename(segmentPath)
504 logger.debug('Adding live sha segment %s.', segmentPath) 516 logger.debug('Adding live sha segment %s.', segmentPath, lTags(videoUUID))
505 517
506 const shaResult = await buildSha256Segment(segmentPath) 518 const shaResult = await buildSha256Segment(segmentPath)
507 519
@@ -516,16 +528,16 @@ class LiveManager {
516 private removeSegmentSha (videoUUID: string, segmentPath: string) { 528 private removeSegmentSha (videoUUID: string, segmentPath: string) {
517 const segmentName = basename(segmentPath) 529 const segmentName = basename(segmentPath)
518 530
519 logger.debug('Removing live sha segment %s.', segmentPath) 531 logger.debug('Removing live sha segment %s.', segmentPath, lTags(videoUUID))
520 532
521 const filesMap = this.segmentsSha256.get(videoUUID) 533 const filesMap = this.segmentsSha256.get(videoUUID)
522 if (!filesMap) { 534 if (!filesMap) {
523 logger.warn('Unknown files map to remove sha for %s.', videoUUID) 535 logger.warn('Unknown files map to remove sha for %s.', videoUUID, lTags(videoUUID))
524 return 536 return
525 } 537 }
526 538
527 if (!filesMap.has(segmentName)) { 539 if (!filesMap.has(segmentName)) {
528 logger.warn('Unknown segment in files map for video %s and segment %s.', videoUUID, segmentPath) 540 logger.warn('Unknown segment in files map for video %s and segment %s.', videoUUID, segmentPath, lTags(videoUUID))
529 return 541 return
530 } 542 }
531 543
@@ -547,7 +559,7 @@ class LiveManager {
547 const rtmpSession = this.getContext().sessions.get(sessionId) 559 const rtmpSession = this.getContext().sessions.get(sessionId)
548 560
549 if (!rtmpSession) { 561 if (!rtmpSession) {
550 logger.warn('Cannot get session %s to check players socket health.', sessionId) 562 logger.warn('Cannot get session %s to check players socket health.', sessionId, lTags(sessionId))
551 return 563 return
552 } 564 }
553 565
@@ -555,7 +567,7 @@ class LiveManager {
555 const playerSession = this.getContext().sessions.get(playerSessionId) 567 const playerSession = this.getContext().sessions.get(playerSessionId)
556 568
557 if (!playerSession) { 569 if (!playerSession) {
558 logger.error('Cannot get player session %s to check socket health.', playerSession) 570 logger.error('Cannot get player session %s to check socket health.', playerSession, lTags(sessionId))
559 continue 571 continue
560 } 572 }
561 573
@@ -576,7 +588,7 @@ class LiveManager {
576 private async updateLiveViews () { 588 private async updateLiveViews () {
577 if (!this.isRunning()) return 589 if (!this.isRunning()) return
578 590
579 if (!isTestInstance()) logger.info('Updating live video views.') 591 if (!isTestInstance()) logger.info('Updating live video views.', lTags())
580 592
581 for (const videoId of this.watchersPerVideo.keys()) { 593 for (const videoId of this.watchersPerVideo.keys()) {
582 const notBefore = new Date().getTime() - VIEW_LIFETIME.LIVE 594 const notBefore = new Date().getTime() - VIEW_LIFETIME.LIVE
@@ -597,15 +609,15 @@ class LiveManager {
597 const newWatchers = watchers.filter(w => w > notBefore) 609 const newWatchers = watchers.filter(w => w > notBefore)
598 this.watchersPerVideo.set(videoId, newWatchers) 610 this.watchersPerVideo.set(videoId, newWatchers)
599 611
600 logger.debug('New live video views for %s is %d.', video.url, numWatchers) 612 logger.debug('New live video views for %s is %d.', video.url, numWatchers, lTags())
601 } 613 }
602 } 614 }
603 615
604 private async handleBrokenLives () { 616 private async handleBrokenLives () {
605 const videoIds = await VideoModel.listPublishedLiveIds() 617 const videoUUIDs = await VideoModel.listPublishedLiveUUIDs()
606 618
607 for (const id of videoIds) { 619 for (const uuid of videoUUIDs) {
608 await this.onEndTransmuxing(id, true) 620 await this.onEndTransmuxing(uuid, true)
609 } 621 }
610 } 622 }
611 623
diff --git a/server/lib/moderation.ts b/server/lib/moderation.ts
index 925d64902..0cefe1648 100644
--- a/server/lib/moderation.ts
+++ b/server/lib/moderation.ts
@@ -23,9 +23,9 @@ import { ActivityCreate } from '../../shared/models/activitypub'
23import { VideoObject } from '../../shared/models/activitypub/objects' 23import { VideoObject } from '../../shared/models/activitypub/objects'
24import { VideoCommentObject } from '../../shared/models/activitypub/objects/video-comment-object' 24import { VideoCommentObject } from '../../shared/models/activitypub/objects/video-comment-object'
25import { LiveVideoCreate, VideoCreate, VideoImportCreate } from '../../shared/models/videos' 25import { LiveVideoCreate, VideoCreate, VideoImportCreate } from '../../shared/models/videos'
26import { VideoCommentCreate } from '../../shared/models/videos/video-comment.model' 26import { VideoCommentCreate } from '../../shared/models/videos/comment/video-comment.model'
27import { UserModel } from '../models/account/user' 27import { ActorModel } from '../models/actor/actor'
28import { ActorModel } from '../models/activitypub/actor' 28import { UserModel } from '../models/user/user'
29import { VideoModel } from '../models/video/video' 29import { VideoModel } from '../models/video/video'
30import { VideoCommentModel } from '../models/video/video-comment' 30import { VideoCommentModel } from '../models/video/video-comment'
31import { sendAbuse } from './activitypub/send/send-flag' 31import { sendAbuse } from './activitypub/send/send-flag'
diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts
index da7f7cc05..1f9ff16df 100644
--- a/server/lib/notifier.ts
+++ b/server/lib/notifier.ts
@@ -17,8 +17,8 @@ import { VideoPrivacy, VideoState } from '../../shared/models/videos'
17import { logger } from '../helpers/logger' 17import { logger } from '../helpers/logger'
18import { CONFIG } from '../initializers/config' 18import { CONFIG } from '../initializers/config'
19import { AccountBlocklistModel } from '../models/account/account-blocklist' 19import { AccountBlocklistModel } from '../models/account/account-blocklist'
20import { UserModel } from '../models/account/user' 20import { UserModel } from '../models/user/user'
21import { UserNotificationModel } from '../models/account/user-notification' 21import { UserNotificationModel } from '../models/user/user-notification'
22import { MAbuseFull, MAbuseMessage, MAccountServer, MActorFollowFull, MApplication, MPlugin } from '../types/models' 22import { MAbuseFull, MAbuseMessage, MAccountServer, MActorFollowFull, MApplication, MPlugin } from '../types/models'
23import { MCommentOwnerVideo, MVideoAccountLight, MVideoFullLight } from '../types/models/video' 23import { MCommentOwnerVideo, MVideoAccountLight, MVideoFullLight } from '../types/models/video'
24import { isBlockedByServerOrAccount } from './blocklist' 24import { isBlockedByServerOrAccount } from './blocklist'
diff --git a/server/lib/plugins/hooks.ts b/server/lib/plugins/hooks.ts
index aa92f03cc..5e97b52a0 100644
--- a/server/lib/plugins/hooks.ts
+++ b/server/lib/plugins/hooks.ts
@@ -1,7 +1,7 @@
1import { ServerActionHookName, ServerFilterHookName } from '../../../shared/models/plugins/server-hook.model'
2import { PluginManager } from './plugin-manager'
3import { logger } from '../../helpers/logger'
4import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
2import { ServerActionHookName, ServerFilterHookName } from '../../../shared/models'
3import { logger } from '../../helpers/logger'
4import { PluginManager } from './plugin-manager'
5 5
6type PromiseFunction <U, T> = (params: U) => Promise<T> | Bluebird<T> 6type PromiseFunction <U, T> = (params: U) => Promise<T> | Bluebird<T>
7type RawFunction <U, T> = (params: U) => T 7type RawFunction <U, T> = (params: U) => T
diff --git a/server/lib/plugins/plugin-helpers-builder.ts b/server/lib/plugins/plugin-helpers-builder.ts
index f1bc24d8b..8487672ba 100644
--- a/server/lib/plugins/plugin-helpers-builder.ts
+++ b/server/lib/plugins/plugin-helpers-builder.ts
@@ -15,9 +15,9 @@ import { MPlugin } from '@server/types/models'
15import { PeerTubeHelpers } from '@server/types/plugins' 15import { PeerTubeHelpers } from '@server/types/plugins'
16import { VideoBlacklistCreate } from '@shared/models' 16import { VideoBlacklistCreate } from '@shared/models'
17import { addAccountInBlocklist, addServerInBlocklist, removeAccountFromBlocklist, removeServerFromBlocklist } from '../blocklist' 17import { addAccountInBlocklist, addServerInBlocklist, removeAccountFromBlocklist, removeServerFromBlocklist } from '../blocklist'
18import { getServerConfig } from '../config' 18import { ServerConfigManager } from '../server-config-manager'
19import { blacklistVideo, unblacklistVideo } from '../video-blacklist' 19import { blacklistVideo, unblacklistVideo } from '../video-blacklist'
20import { UserModel } from '@server/models/account/user' 20import { UserModel } from '@server/models/user/user'
21 21
22function buildPluginHelpers (pluginModel: MPlugin, npmName: string): PeerTubeHelpers { 22function buildPluginHelpers (pluginModel: MPlugin, npmName: string): PeerTubeHelpers {
23 const logger = buildPluginLogger(npmName) 23 const logger = buildPluginLogger(npmName)
@@ -147,7 +147,7 @@ function buildConfigHelpers () {
147 }, 147 },
148 148
149 getServerConfig () { 149 getServerConfig () {
150 return getServerConfig() 150 return ServerConfigManager.Instance.getServerConfig()
151 } 151 }
152 } 152 }
153} 153}
diff --git a/server/lib/plugins/plugin-index.ts b/server/lib/plugins/plugin-index.ts
index 165bc91b3..119cee8e0 100644
--- a/server/lib/plugins/plugin-index.ts
+++ b/server/lib/plugins/plugin-index.ts
@@ -1,16 +1,16 @@
1import { sanitizeUrl } from '@server/helpers/core-utils' 1import { sanitizeUrl } from '@server/helpers/core-utils'
2import { ResultList } from '../../../shared/models' 2import { logger } from '@server/helpers/logger'
3import { PeertubePluginIndexList } from '../../../shared/models/plugins/peertube-plugin-index-list.model' 3import { doJSONRequest } from '@server/helpers/requests'
4import { PeerTubePluginIndex } from '../../../shared/models/plugins/peertube-plugin-index.model' 4import { CONFIG } from '@server/initializers/config'
5import { PEERTUBE_VERSION } from '@server/initializers/constants'
6import { PluginModel } from '@server/models/server/plugin'
5import { 7import {
8 PeerTubePluginIndex,
9 PeertubePluginIndexList,
6 PeertubePluginLatestVersionRequest, 10 PeertubePluginLatestVersionRequest,
7 PeertubePluginLatestVersionResponse 11 PeertubePluginLatestVersionResponse,
8} from '../../../shared/models/plugins/peertube-plugin-latest-version.model' 12 ResultList
9import { logger } from '../../helpers/logger' 13} from '@shared/models'
10import { doJSONRequest } from '../../helpers/requests'
11import { CONFIG } from '../../initializers/config'
12import { PEERTUBE_VERSION } from '../../initializers/constants'
13import { PluginModel } from '../../models/server/plugin'
14import { PluginManager } from './plugin-manager' 14import { PluginManager } from './plugin-manager'
15 15
16async function listAvailablePluginsFromIndex (options: PeertubePluginIndexList) { 16async function listAvailablePluginsFromIndex (options: PeertubePluginIndexList) {
diff --git a/server/lib/plugins/plugin-manager.ts b/server/lib/plugins/plugin-manager.ts
index ba9814383..6b9a255a4 100644
--- a/server/lib/plugins/plugin-manager.ts
+++ b/server/lib/plugins/plugin-manager.ts
@@ -4,16 +4,11 @@ import { createReadStream, createWriteStream } from 'fs'
4import { ensureDir, outputFile, readJSON } from 'fs-extra' 4import { ensureDir, outputFile, readJSON } from 'fs-extra'
5import { basename, join } from 'path' 5import { basename, join } from 'path'
6import { MOAuthTokenUser, MUser } from '@server/types/models' 6import { MOAuthTokenUser, MUser } from '@server/types/models'
7import { RegisterServerHookOptions } from '@shared/models/plugins/register-server-hook.model' 7import { getCompleteLocale } from '@shared/core-utils'
8import { ClientScript, PluginPackageJson, PluginTranslation, PluginTranslationPaths, RegisterServerHookOptions } from '@shared/models'
8import { getHookType, internalRunHook } from '../../../shared/core-utils/plugins/hooks' 9import { getHookType, internalRunHook } from '../../../shared/core-utils/plugins/hooks'
9import {
10 ClientScript,
11 PluginPackageJson,
12 PluginTranslationPaths as PackagePluginTranslations
13} from '../../../shared/models/plugins/plugin-package-json.model'
14import { PluginTranslation } from '../../../shared/models/plugins/plugin-translation.model'
15import { PluginType } from '../../../shared/models/plugins/plugin.type' 10import { PluginType } from '../../../shared/models/plugins/plugin.type'
16import { ServerHook, ServerHookName } from '../../../shared/models/plugins/server-hook.model' 11import { ServerHook, ServerHookName } from '../../../shared/models/plugins/server/server-hook.model'
17import { isLibraryCodeValid, isPackageJSONValid } from '../../helpers/custom-validators/plugins' 12import { isLibraryCodeValid, isPackageJSONValid } from '../../helpers/custom-validators/plugins'
18import { logger } from '../../helpers/logger' 13import { logger } from '../../helpers/logger'
19import { CONFIG } from '../../initializers/config' 14import { CONFIG } from '../../initializers/config'
@@ -23,7 +18,6 @@ import { PluginLibrary, RegisterServerAuthExternalOptions, RegisterServerAuthPas
23import { ClientHtml } from '../client-html' 18import { ClientHtml } from '../client-html'
24import { RegisterHelpers } from './register-helpers' 19import { RegisterHelpers } from './register-helpers'
25import { installNpmPlugin, installNpmPluginFromDisk, removeNpmPlugin } from './yarn' 20import { installNpmPlugin, installNpmPluginFromDisk, removeNpmPlugin } from './yarn'
26import { getCompleteLocale } from '@shared/core-utils'
27 21
28export interface RegisteredPlugin { 22export interface RegisteredPlugin {
29 npmName: string 23 npmName: string
@@ -443,7 +437,7 @@ export class PluginManager implements ServerHook {
443 437
444 // ###################### Translations ###################### 438 // ###################### Translations ######################
445 439
446 private async addTranslations (plugin: PluginModel, npmName: string, translationPaths: PackagePluginTranslations) { 440 private async addTranslations (plugin: PluginModel, npmName: string, translationPaths: PluginTranslationPaths) {
447 for (const locale of Object.keys(translationPaths)) { 441 for (const locale of Object.keys(translationPaths)) {
448 const path = translationPaths[locale] 442 const path = translationPaths[locale]
449 const json = await readJSON(join(this.getPluginPath(plugin.name, plugin.type), path)) 443 const json = await readJSON(join(this.getPluginPath(plugin.name, plugin.type), path))
diff --git a/server/lib/plugins/register-helpers.ts b/server/lib/plugins/register-helpers.ts
index aa69ca2a2..f5b573370 100644
--- a/server/lib/plugins/register-helpers.ts
+++ b/server/lib/plugins/register-helpers.ts
@@ -26,10 +26,10 @@ import {
26 PluginVideoLicenceManager, 26 PluginVideoLicenceManager,
27 PluginVideoPrivacyManager, 27 PluginVideoPrivacyManager,
28 RegisterServerHookOptions, 28 RegisterServerHookOptions,
29 RegisterServerSettingOptions 29 RegisterServerSettingOptions,
30 serverHookObject
30} from '@shared/models' 31} from '@shared/models'
31import { serverHookObject } from '@shared/models/plugins/server-hook.model' 32import { VideoTranscodingProfilesManager } from '../transcoding/video-transcoding-profiles'
32import { VideoTranscodingProfilesManager } from '../video-transcoding-profiles'
33import { buildPluginHelpers } from './plugin-helpers-builder' 33import { buildPluginHelpers } from './plugin-helpers-builder'
34 34
35type AlterableVideoConstant = 'language' | 'licence' | 'category' | 'privacy' | 'playlistPrivacy' 35type AlterableVideoConstant = 'language' | 'licence' | 'category' | 'privacy' | 'playlistPrivacy'
diff --git a/server/lib/redundancy.ts b/server/lib/redundancy.ts
index da620b607..2a9241249 100644
--- a/server/lib/redundancy.ts
+++ b/server/lib/redundancy.ts
@@ -1,12 +1,12 @@
1import { VideoRedundancyModel } from '../models/redundancy/video-redundancy'
2import { sendUndoCacheFile } from './activitypub/send'
3import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
4import { MActorSignature, MVideoRedundancyVideo } from '@server/types/models'
5import { CONFIG } from '@server/initializers/config'
6import { logger } from '@server/helpers/logger' 2import { logger } from '@server/helpers/logger'
7import { ActorFollowModel } from '@server/models/activitypub/actor-follow' 3import { CONFIG } from '@server/initializers/config'
8import { Activity } from '@shared/models' 4import { ActorFollowModel } from '@server/models/actor/actor-follow'
9import { getServerActor } from '@server/models/application/application' 5import { getServerActor } from '@server/models/application/application'
6import { MActorSignature, MVideoRedundancyVideo } from '@server/types/models'
7import { Activity } from '@shared/models'
8import { VideoRedundancyModel } from '../models/redundancy/video-redundancy'
9import { sendUndoCacheFile } from './activitypub/send'
10 10
11async function removeVideoRedundancy (videoRedundancy: MVideoRedundancyVideo, t?: Transaction) { 11async function removeVideoRedundancy (videoRedundancy: MVideoRedundancyVideo, t?: Transaction) {
12 const serverActor = await getServerActor() 12 const serverActor = await getServerActor()
diff --git a/server/lib/schedulers/actor-follow-scheduler.ts b/server/lib/schedulers/actor-follow-scheduler.ts
index 598c0211f..1b80316e9 100644
--- a/server/lib/schedulers/actor-follow-scheduler.ts
+++ b/server/lib/schedulers/actor-follow-scheduler.ts
@@ -1,9 +1,9 @@
1import { isTestInstance } from '../../helpers/core-utils' 1import { isTestInstance } from '../../helpers/core-utils'
2import { logger } from '../../helpers/logger' 2import { logger } from '../../helpers/logger'
3import { ActorFollowModel } from '../../models/activitypub/actor-follow'
4import { AbstractScheduler } from './abstract-scheduler'
5import { ACTOR_FOLLOW_SCORE, SCHEDULER_INTERVALS_MS } from '../../initializers/constants' 3import { ACTOR_FOLLOW_SCORE, SCHEDULER_INTERVALS_MS } from '../../initializers/constants'
4import { ActorFollowModel } from '../../models/actor/actor-follow'
6import { ActorFollowScoreCache } from '../files-cache' 5import { ActorFollowScoreCache } from '../files-cache'
6import { AbstractScheduler } from './abstract-scheduler'
7 7
8export class ActorFollowScheduler extends AbstractScheduler { 8export class ActorFollowScheduler extends AbstractScheduler {
9 9
diff --git a/server/lib/schedulers/auto-follow-index-instances.ts b/server/lib/schedulers/auto-follow-index-instances.ts
index 0b8cd1389..aaa5feed5 100644
--- a/server/lib/schedulers/auto-follow-index-instances.ts
+++ b/server/lib/schedulers/auto-follow-index-instances.ts
@@ -1,7 +1,7 @@
1import { chunk } from 'lodash' 1import { chunk } from 'lodash'
2import { doJSONRequest } from '@server/helpers/requests' 2import { doJSONRequest } from '@server/helpers/requests'
3import { JobQueue } from '@server/lib/job-queue' 3import { JobQueue } from '@server/lib/job-queue'
4import { ActorFollowModel } from '@server/models/activitypub/actor-follow' 4import { ActorFollowModel } from '@server/models/actor/actor-follow'
5import { getServerActor } from '@server/models/application/application' 5import { getServerActor } from '@server/models/application/application'
6import { logger } from '../../helpers/logger' 6import { logger } from '../../helpers/logger'
7import { CONFIG } from '../../initializers/config' 7import { CONFIG } from '../../initializers/config'
diff --git a/server/lib/schedulers/remove-old-history-scheduler.ts b/server/lib/schedulers/remove-old-history-scheduler.ts
index 17a42b2c4..225669ea2 100644
--- a/server/lib/schedulers/remove-old-history-scheduler.ts
+++ b/server/lib/schedulers/remove-old-history-scheduler.ts
@@ -1,7 +1,7 @@
1import { logger } from '../../helpers/logger' 1import { logger } from '../../helpers/logger'
2import { AbstractScheduler } from './abstract-scheduler' 2import { AbstractScheduler } from './abstract-scheduler'
3import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' 3import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants'
4import { UserVideoHistoryModel } from '../../models/account/user-video-history' 4import { UserVideoHistoryModel } from '../../models/user/user-video-history'
5import { CONFIG } from '../../initializers/config' 5import { CONFIG } from '../../initializers/config'
6 6
7export class RemoveOldHistoryScheduler extends AbstractScheduler { 7export class RemoveOldHistoryScheduler extends AbstractScheduler {
diff --git a/server/lib/schedulers/youtube-dl-update-scheduler.ts b/server/lib/schedulers/youtube-dl-update-scheduler.ts
index aefe6aba4..898691c13 100644
--- a/server/lib/schedulers/youtube-dl-update-scheduler.ts
+++ b/server/lib/schedulers/youtube-dl-update-scheduler.ts
@@ -1,6 +1,6 @@
1import { AbstractScheduler } from './abstract-scheduler' 1import { YoutubeDL } from '@server/helpers/youtube-dl'
2import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' 2import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants'
3import { updateYoutubeDLBinary } from '../../helpers/youtube-dl' 3import { AbstractScheduler } from './abstract-scheduler'
4 4
5export class YoutubeDlUpdateScheduler extends AbstractScheduler { 5export class YoutubeDlUpdateScheduler extends AbstractScheduler {
6 6
@@ -13,7 +13,7 @@ export class YoutubeDlUpdateScheduler extends AbstractScheduler {
13 } 13 }
14 14
15 protected internalExecute () { 15 protected internalExecute () {
16 return updateYoutubeDLBinary() 16 return YoutubeDL.updateYoutubeDLBinary()
17 } 17 }
18 18
19 static get Instance () { 19 static get Instance () {
diff --git a/server/lib/server-config-manager.ts b/server/lib/server-config-manager.ts
new file mode 100644
index 000000000..25a770c6b
--- /dev/null
+++ b/server/lib/server-config-manager.ts
@@ -0,0 +1,304 @@
1import { isSignupAllowed, isSignupAllowedForCurrentIP } from '@server/helpers/signup'
2import { getServerCommit } from '@server/helpers/utils'
3import { CONFIG, isEmailEnabled } from '@server/initializers/config'
4import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants'
5import { ActorCustomPageModel } from '@server/models/account/actor-custom-page'
6import { HTMLServerConfig, RegisteredExternalAuthConfig, RegisteredIdAndPassAuthConfig, ServerConfig } from '@shared/models'
7import { Hooks } from './plugins/hooks'
8import { PluginManager } from './plugins/plugin-manager'
9import { getThemeOrDefault } from './plugins/theme-utils'
10import { VideoTranscodingProfilesManager } from './transcoding/video-transcoding-profiles'
11
12/**
13 *
14 * Used to send the server config to clients (using REST/API or plugins API)
15 * We need a singleton class to manage config state depending on external events (to build menu entries etc)
16 *
17 */
18
19class ServerConfigManager {
20
21 private static instance: ServerConfigManager
22
23 private serverCommit: string
24
25 private homepageEnabled = false
26
27 private constructor () {}
28
29 async init () {
30 const instanceHomepage = await ActorCustomPageModel.loadInstanceHomepage()
31
32 this.updateHomepageState(instanceHomepage?.content)
33 }
34
35 updateHomepageState (content: string) {
36 this.homepageEnabled = !!content
37 }
38
39 async getHTMLServerConfig (): Promise<HTMLServerConfig> {
40 if (this.serverCommit === undefined) this.serverCommit = await getServerCommit()
41
42 const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME)
43
44 return {
45 instance: {
46 name: CONFIG.INSTANCE.NAME,
47 shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION,
48 isNSFW: CONFIG.INSTANCE.IS_NSFW,
49 defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
50 defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE,
51 customizations: {
52 javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT,
53 css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS
54 }
55 },
56 search: {
57 remoteUri: {
58 users: CONFIG.SEARCH.REMOTE_URI.USERS,
59 anonymous: CONFIG.SEARCH.REMOTE_URI.ANONYMOUS
60 },
61 searchIndex: {
62 enabled: CONFIG.SEARCH.SEARCH_INDEX.ENABLED,
63 url: CONFIG.SEARCH.SEARCH_INDEX.URL,
64 disableLocalSearch: CONFIG.SEARCH.SEARCH_INDEX.DISABLE_LOCAL_SEARCH,
65 isDefaultSearch: CONFIG.SEARCH.SEARCH_INDEX.IS_DEFAULT_SEARCH
66 }
67 },
68 plugin: {
69 registered: this.getRegisteredPlugins(),
70 registeredExternalAuths: this.getExternalAuthsPlugins(),
71 registeredIdAndPassAuths: this.getIdAndPassAuthPlugins()
72 },
73 theme: {
74 registered: this.getRegisteredThemes(),
75 default: defaultTheme
76 },
77 email: {
78 enabled: isEmailEnabled()
79 },
80 contactForm: {
81 enabled: CONFIG.CONTACT_FORM.ENABLED
82 },
83 serverVersion: PEERTUBE_VERSION,
84 serverCommit: this.serverCommit,
85 transcoding: {
86 hls: {
87 enabled: CONFIG.TRANSCODING.HLS.ENABLED
88 },
89 webtorrent: {
90 enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED
91 },
92 enabledResolutions: this.getEnabledResolutions('vod'),
93 profile: CONFIG.TRANSCODING.PROFILE,
94 availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('vod')
95 },
96 live: {
97 enabled: CONFIG.LIVE.ENABLED,
98
99 allowReplay: CONFIG.LIVE.ALLOW_REPLAY,
100 maxDuration: CONFIG.LIVE.MAX_DURATION,
101 maxInstanceLives: CONFIG.LIVE.MAX_INSTANCE_LIVES,
102 maxUserLives: CONFIG.LIVE.MAX_USER_LIVES,
103
104 transcoding: {
105 enabled: CONFIG.LIVE.TRANSCODING.ENABLED,
106 enabledResolutions: this.getEnabledResolutions('live'),
107 profile: CONFIG.LIVE.TRANSCODING.PROFILE,
108 availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('live')
109 },
110
111 rtmp: {
112 port: CONFIG.LIVE.RTMP.PORT
113 }
114 },
115 import: {
116 videos: {
117 http: {
118 enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED
119 },
120 torrent: {
121 enabled: CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED
122 }
123 }
124 },
125 autoBlacklist: {
126 videos: {
127 ofUsers: {
128 enabled: CONFIG.AUTO_BLACKLIST.VIDEOS.OF_USERS.ENABLED
129 }
130 }
131 },
132 avatar: {
133 file: {
134 size: {
135 max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
136 },
137 extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
138 }
139 },
140 banner: {
141 file: {
142 size: {
143 max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
144 },
145 extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
146 }
147 },
148 video: {
149 image: {
150 extensions: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME,
151 size: {
152 max: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max
153 }
154 },
155 file: {
156 extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME
157 }
158 },
159 videoCaption: {
160 file: {
161 size: {
162 max: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE.max
163 },
164 extensions: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.EXTNAME
165 }
166 },
167 user: {
168 videoQuota: CONFIG.USER.VIDEO_QUOTA,
169 videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY
170 },
171 trending: {
172 videos: {
173 intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS,
174 algorithms: {
175 enabled: CONFIG.TRENDING.VIDEOS.ALGORITHMS.ENABLED,
176 default: CONFIG.TRENDING.VIDEOS.ALGORITHMS.DEFAULT
177 }
178 }
179 },
180 tracker: {
181 enabled: CONFIG.TRACKER.ENABLED
182 },
183
184 followings: {
185 instance: {
186 autoFollowIndex: {
187 indexUrl: CONFIG.FOLLOWINGS.INSTANCE.AUTO_FOLLOW_INDEX.INDEX_URL
188 }
189 }
190 },
191
192 broadcastMessage: {
193 enabled: CONFIG.BROADCAST_MESSAGE.ENABLED,
194 message: CONFIG.BROADCAST_MESSAGE.MESSAGE,
195 level: CONFIG.BROADCAST_MESSAGE.LEVEL,
196 dismissable: CONFIG.BROADCAST_MESSAGE.DISMISSABLE
197 },
198
199 homepage: {
200 enabled: this.homepageEnabled
201 }
202 }
203 }
204
205 async getServerConfig (ip?: string): Promise<ServerConfig> {
206 const { allowed } = await Hooks.wrapPromiseFun(
207 isSignupAllowed,
208 {
209 ip
210 },
211 'filter:api.user.signup.allowed.result'
212 )
213
214 const allowedForCurrentIP = isSignupAllowedForCurrentIP(ip)
215
216 const signup = {
217 allowed,
218 allowedForCurrentIP,
219 minimumAge: CONFIG.SIGNUP.MINIMUM_AGE,
220 requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION
221 }
222
223 const htmlConfig = await this.getHTMLServerConfig()
224
225 return { ...htmlConfig, signup }
226 }
227
228 getRegisteredThemes () {
229 return PluginManager.Instance.getRegisteredThemes()
230 .map(t => ({
231 name: t.name,
232 version: t.version,
233 description: t.description,
234 css: t.css,
235 clientScripts: t.clientScripts
236 }))
237 }
238
239 getRegisteredPlugins () {
240 return PluginManager.Instance.getRegisteredPlugins()
241 .map(p => ({
242 name: p.name,
243 version: p.version,
244 description: p.description,
245 clientScripts: p.clientScripts
246 }))
247 }
248
249 getEnabledResolutions (type: 'vod' | 'live') {
250 const transcoding = type === 'vod'
251 ? CONFIG.TRANSCODING
252 : CONFIG.LIVE.TRANSCODING
253
254 return Object.keys(transcoding.RESOLUTIONS)
255 .filter(key => transcoding.ENABLED && transcoding.RESOLUTIONS[key] === true)
256 .map(r => parseInt(r, 10))
257 }
258
259 private getIdAndPassAuthPlugins () {
260 const result: RegisteredIdAndPassAuthConfig[] = []
261
262 for (const p of PluginManager.Instance.getIdAndPassAuths()) {
263 for (const auth of p.idAndPassAuths) {
264 result.push({
265 npmName: p.npmName,
266 name: p.name,
267 version: p.version,
268 authName: auth.authName,
269 weight: auth.getWeight()
270 })
271 }
272 }
273
274 return result
275 }
276
277 private getExternalAuthsPlugins () {
278 const result: RegisteredExternalAuthConfig[] = []
279
280 for (const p of PluginManager.Instance.getExternalAuths()) {
281 for (const auth of p.externalAuths) {
282 result.push({
283 npmName: p.npmName,
284 name: p.name,
285 version: p.version,
286 authName: auth.authName,
287 authDisplayName: auth.authDisplayName()
288 })
289 }
290 }
291
292 return result
293 }
294
295 static get Instance () {
296 return this.instance || (this.instance = new this())
297 }
298}
299
300// ---------------------------------------------------------------------------
301
302export {
303 ServerConfigManager
304}
diff --git a/server/lib/stat-manager.ts b/server/lib/stat-manager.ts
index 09ba208bd..25ed21927 100644
--- a/server/lib/stat-manager.ts
+++ b/server/lib/stat-manager.ts
@@ -1,6 +1,6 @@
1import { CONFIG } from '@server/initializers/config' 1import { CONFIG } from '@server/initializers/config'
2import { UserModel } from '@server/models/account/user' 2import { UserModel } from '@server/models/user/user'
3import { ActorFollowModel } from '@server/models/activitypub/actor-follow' 3import { ActorFollowModel } from '@server/models/actor/actor-follow'
4import { VideoRedundancyModel } from '@server/models/redundancy/video-redundancy' 4import { VideoRedundancyModel } from '@server/models/redundancy/video-redundancy'
5import { VideoModel } from '@server/models/video/video' 5import { VideoModel } from '@server/models/video/video'
6import { VideoChannelModel } from '@server/models/video/video-channel' 6import { VideoChannelModel } from '@server/models/video/video-channel'
diff --git a/server/lib/video-transcoding-profiles.ts b/server/lib/transcoding/video-transcoding-profiles.ts
index 81f5e1962..c5ea72a5f 100644
--- a/server/lib/video-transcoding-profiles.ts
+++ b/server/lib/transcoding/video-transcoding-profiles.ts
@@ -1,6 +1,6 @@
1import { logger } from '@server/helpers/logger' 1import { logger } from '@server/helpers/logger'
2import { AvailableEncoders, EncoderOptionsBuilder, getTargetBitrate, VideoResolution } from '../../shared/models/videos' 2import { AvailableEncoders, EncoderOptionsBuilder, getTargetBitrate, VideoResolution } from '../../../shared/models/videos'
3import { buildStreamSuffix, resetSupportedEncoders } from '../helpers/ffmpeg-utils' 3import { buildStreamSuffix, resetSupportedEncoders } from '../../helpers/ffmpeg-utils'
4import { 4import {
5 canDoQuickAudioTranscode, 5 canDoQuickAudioTranscode,
6 ffprobePromise, 6 ffprobePromise,
@@ -8,8 +8,8 @@ import {
8 getMaxAudioBitrate, 8 getMaxAudioBitrate,
9 getVideoFileBitrate, 9 getVideoFileBitrate,
10 getVideoStreamFromFile 10 getVideoStreamFromFile
11} from '../helpers/ffprobe-utils' 11} from '../../helpers/ffprobe-utils'
12import { VIDEO_TRANSCODING_FPS } from '../initializers/constants' 12import { VIDEO_TRANSCODING_FPS } from '../../initializers/constants'
13 13
14/** 14/**
15 * 15 *
diff --git a/server/lib/video-transcoding.ts b/server/lib/transcoding/video-transcoding.ts
index c949dca2e..5df192575 100644
--- a/server/lib/video-transcoding.ts
+++ b/server/lib/transcoding/video-transcoding.ts
@@ -3,17 +3,17 @@ import { copyFile, ensureDir, move, remove, stat } from 'fs-extra'
3import { basename, extname as extnameUtil, join } from 'path' 3import { basename, extname as extnameUtil, join } from 'path'
4import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' 4import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent'
5import { MStreamingPlaylistFilesVideo, MVideoFile, MVideoFullLight } from '@server/types/models' 5import { MStreamingPlaylistFilesVideo, MVideoFile, MVideoFullLight } from '@server/types/models'
6import { VideoResolution } from '../../shared/models/videos' 6import { VideoResolution } from '../../../shared/models/videos'
7import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' 7import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type'
8import { transcode, TranscodeOptions, TranscodeOptionsType } from '../helpers/ffmpeg-utils' 8import { transcode, TranscodeOptions, TranscodeOptionsType } from '../../helpers/ffmpeg-utils'
9import { canDoQuickTranscode, getDurationFromVideoFile, getMetadataFromFile, getVideoFileFPS } from '../helpers/ffprobe-utils' 9import { canDoQuickTranscode, getDurationFromVideoFile, getMetadataFromFile, getVideoFileFPS } from '../../helpers/ffprobe-utils'
10import { logger } from '../helpers/logger' 10import { logger } from '../../helpers/logger'
11import { CONFIG } from '../initializers/config' 11import { CONFIG } from '../../initializers/config'
12import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../initializers/constants' 12import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../../initializers/constants'
13import { VideoFileModel } from '../models/video/video-file' 13import { VideoFileModel } from '../../models/video/video-file'
14import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' 14import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist'
15import { updateMasterHLSPlaylist, updateSha256VODSegments } from './hls' 15import { updateMasterHLSPlaylist, updateSha256VODSegments } from '../hls'
16import { generateVideoFilename, generateVideoStreamingPlaylistName, getVideoFilePath } from './video-paths' 16import { generateVideoFilename, generateVideoStreamingPlaylistName, getVideoFilePath } from '../video-paths'
17import { VideoTranscodingProfilesManager } from './video-transcoding-profiles' 17import { VideoTranscodingProfilesManager } from './video-transcoding-profiles'
18 18
19/** 19/**
@@ -215,16 +215,6 @@ function generateHlsPlaylistResolution (options: {
215 }) 215 })
216} 216}
217 217
218function getEnabledResolutions (type: 'vod' | 'live') {
219 const transcoding = type === 'vod'
220 ? CONFIG.TRANSCODING
221 : CONFIG.LIVE.TRANSCODING
222
223 return Object.keys(transcoding.RESOLUTIONS)
224 .filter(key => transcoding.ENABLED && transcoding.RESOLUTIONS[key] === true)
225 .map(r => parseInt(r, 10))
226}
227
228// --------------------------------------------------------------------------- 218// ---------------------------------------------------------------------------
229 219
230export { 220export {
@@ -232,8 +222,7 @@ export {
232 generateHlsPlaylistResolutionFromTS, 222 generateHlsPlaylistResolutionFromTS,
233 optimizeOriginalVideofile, 223 optimizeOriginalVideofile,
234 transcodeNewWebTorrentResolution, 224 transcodeNewWebTorrentResolution,
235 mergeAudioVideofile, 225 mergeAudioVideofile
236 getEnabledResolutions
237} 226}
238 227
239// --------------------------------------------------------------------------- 228// ---------------------------------------------------------------------------
diff --git a/server/lib/user.ts b/server/lib/user.ts
index 9b0a0a2f1..8a6fcebc7 100644
--- a/server/lib/user.ts
+++ b/server/lib/user.ts
@@ -1,14 +1,15 @@
1import { Transaction } from 'sequelize/types' 1import { Transaction } from 'sequelize/types'
2import { v4 as uuidv4 } from 'uuid' 2import { v4 as uuidv4 } from 'uuid'
3import { UserModel } from '@server/models/account/user' 3import { UserModel } from '@server/models/user/user'
4import { MActorDefault } from '@server/types/models/actor'
4import { ActivityPubActorType } from '../../shared/models/activitypub' 5import { ActivityPubActorType } from '../../shared/models/activitypub'
5import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users' 6import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users'
6import { SERVER_ACTOR_NAME, WEBSERVER } from '../initializers/constants' 7import { SERVER_ACTOR_NAME, WEBSERVER } from '../initializers/constants'
7import { sequelizeTypescript } from '../initializers/database' 8import { sequelizeTypescript } from '../initializers/database'
8import { AccountModel } from '../models/account/account' 9import { AccountModel } from '../models/account/account'
9import { UserNotificationSettingModel } from '../models/account/user-notification-setting' 10import { ActorModel } from '../models/actor/actor'
10import { ActorModel } from '../models/activitypub/actor' 11import { UserNotificationSettingModel } from '../models/user/user-notification-setting'
11import { MAccountDefault, MActorDefault, MChannelActor } from '../types/models' 12import { MAccountDefault, MChannelActor } from '../types/models'
12import { MUser, MUserDefault, MUserId } from '../types/models/user' 13import { MUser, MUserDefault, MUserId } from '../types/models/user'
13import { buildActorInstance, generateAndSaveActorKeys } from './activitypub/actor' 14import { buildActorInstance, generateAndSaveActorKeys } from './activitypub/actor'
14import { getLocalAccountActivityPubUrl } from './activitypub/url' 15import { getLocalAccountActivityPubUrl } from './activitypub/url'
diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts
index 0476cb2d5..d57e832fe 100644
--- a/server/lib/video-channel.ts
+++ b/server/lib/video-channel.ts
@@ -1,5 +1,4 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import { v4 as uuidv4 } from 'uuid'
3import { VideoChannelCreate } from '../../shared/models' 2import { VideoChannelCreate } from '../../shared/models'
4import { VideoModel } from '../models/video/video' 3import { VideoModel } from '../models/video/video'
5import { VideoChannelModel } from '../models/video/video-channel' 4import { VideoChannelModel } from '../models/video/video-channel'
@@ -9,9 +8,8 @@ import { getLocalVideoChannelActivityPubUrl } from './activitypub/url'
9import { federateVideoIfNeeded } from './activitypub/videos' 8import { federateVideoIfNeeded } from './activitypub/videos'
10 9
11async function createLocalVideoChannel (videoChannelInfo: VideoChannelCreate, account: MAccountId, t: Sequelize.Transaction) { 10async function createLocalVideoChannel (videoChannelInfo: VideoChannelCreate, account: MAccountId, t: Sequelize.Transaction) {
12 const uuid = uuidv4()
13 const url = getLocalVideoChannelActivityPubUrl(videoChannelInfo.name) 11 const url = getLocalVideoChannelActivityPubUrl(videoChannelInfo.name)
14 const actorInstance = buildActorInstance('Group', url, videoChannelInfo.name, uuid) 12 const actorInstance = buildActorInstance('Group', url, videoChannelInfo.name)
15 13
16 const actorInstanceCreated = await actorInstance.save({ transaction: t }) 14 const actorInstanceCreated = await actorInstance.save({ transaction: t })
17 15
diff --git a/server/lib/video-comment.ts b/server/lib/video-comment.ts
index 736ebb2f8..51a9c747e 100644
--- a/server/lib/video-comment.ts
+++ b/server/lib/video-comment.ts
@@ -3,7 +3,7 @@ import * as Sequelize from 'sequelize'
3import { logger } from '@server/helpers/logger' 3import { logger } from '@server/helpers/logger'
4import { sequelizeTypescript } from '@server/initializers/database' 4import { sequelizeTypescript } from '@server/initializers/database'
5import { ResultList } from '../../shared/models' 5import { ResultList } from '../../shared/models'
6import { VideoCommentThreadTree } from '../../shared/models/videos/video-comment.model' 6import { VideoCommentThreadTree } from '../../shared/models/videos/comment/video-comment.model'
7import { VideoCommentModel } from '../models/video/video-comment' 7import { VideoCommentModel } from '../models/video/video-comment'
8import { MAccountDefault, MComment, MCommentOwnerVideo, MCommentOwnerVideoReply, MVideoFullLight } from '../types/models' 8import { MAccountDefault, MComment, MCommentOwnerVideo, MCommentOwnerVideoReply, MVideoFullLight } from '../types/models'
9import { sendCreateVideoComment, sendDeleteVideoComment } from './activitypub/send' 9import { sendCreateVideoComment, sendDeleteVideoComment } from './activitypub/send'
diff --git a/server/lib/video.ts b/server/lib/video.ts
index 21e4b7ff2..d26cf85cd 100644
--- a/server/lib/video.ts
+++ b/server/lib/video.ts
@@ -28,6 +28,8 @@ function buildLocalVideoFromReq (videoInfo: VideoCreate, channelId: number): Fil
28 privacy: videoInfo.privacy || VideoPrivacy.PRIVATE, 28 privacy: videoInfo.privacy || VideoPrivacy.PRIVATE,
29 channelId: channelId, 29 channelId: channelId,
30 originallyPublishedAt: videoInfo.originallyPublishedAt 30 originallyPublishedAt: videoInfo.originallyPublishedAt
31 ? new Date(videoInfo.originallyPublishedAt)
32 : null
31 } 33 }
32} 34}
33 35