aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/initializers
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-09-17 09:20:52 +0200
committerChocobozzz <chocobozzz@cpy.re>2020-11-09 15:33:04 +0100
commitc6c0fa6cd8fe8f752463d8982c3dbcd448739c4e (patch)
tree79304b0152b0a38d33b26e65d4acdad0da4032a7 /server/initializers
parent110d463fece85e87a26aca48a6048ae0017a27b3 (diff)
downloadPeerTube-c6c0fa6cd8fe8f752463d8982c3dbcd448739c4e.tar.gz
PeerTube-c6c0fa6cd8fe8f752463d8982c3dbcd448739c4e.tar.zst
PeerTube-c6c0fa6cd8fe8f752463d8982c3dbcd448739c4e.zip
Live streaming implementation first step
Diffstat (limited to 'server/initializers')
-rw-r--r--server/initializers/config.ts21
-rw-r--r--server/initializers/constants.ts50
-rw-r--r--server/initializers/database.ts10
-rw-r--r--server/initializers/migrations/0535-video-live.ts39
-rw-r--r--server/initializers/migrations/0540-video-file-infohash.ts26
5 files changed, 127 insertions, 19 deletions
diff --git a/server/initializers/config.ts b/server/initializers/config.ts
index b40e525a5..7a8200ed9 100644
--- a/server/initializers/config.ts
+++ b/server/initializers/config.ts
@@ -198,6 +198,27 @@ const CONFIG = {
198 get ENABLED () { return config.get<boolean>('transcoding.webtorrent.enabled') } 198 get ENABLED () { return config.get<boolean>('transcoding.webtorrent.enabled') }
199 } 199 }
200 }, 200 },
201 LIVE: {
202 get ENABLED () { return config.get<boolean>('live.enabled') },
203
204 RTMP: {
205 get PORT () { return config.get<number>('live.rtmp.port') }
206 },
207
208 TRANSCODING: {
209 get ENABLED () { return config.get<boolean>('live.transcoding.enabled') },
210 get THREADS () { return config.get<number>('live.transcoding.threads') },
211
212 RESOLUTIONS: {
213 get '240p' () { return config.get<boolean>('live.transcoding.resolutions.240p') },
214 get '360p' () { return config.get<boolean>('live.transcoding.resolutions.360p') },
215 get '480p' () { return config.get<boolean>('live.transcoding.resolutions.480p') },
216 get '720p' () { return config.get<boolean>('live.transcoding.resolutions.720p') },
217 get '1080p' () { return config.get<boolean>('live.transcoding.resolutions.1080p') },
218 get '2160p' () { return config.get<boolean>('live.transcoding.resolutions.2160p') }
219 }
220 }
221 },
201 IMPORT: { 222 IMPORT: {
202 VIDEOS: { 223 VIDEOS: {
203 HTTP: { 224 HTTP: {
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 171e9e9c2..606eeba2d 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -23,7 +23,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
23 23
24// --------------------------------------------------------------------------- 24// ---------------------------------------------------------------------------
25 25
26const LAST_MIGRATION_VERSION = 530 26const LAST_MIGRATION_VERSION = 540
27 27
28// --------------------------------------------------------------------------- 28// ---------------------------------------------------------------------------
29 29
@@ -50,7 +50,8 @@ const WEBSERVER = {
50 SCHEME: '', 50 SCHEME: '',
51 WS: '', 51 WS: '',
52 HOSTNAME: '', 52 HOSTNAME: '',
53 PORT: 0 53 PORT: 0,
54 RTMP_URL: ''
54} 55}
55 56
56// Sortable columns per schema 57// Sortable columns per schema
@@ -264,7 +265,7 @@ const CONSTRAINTS_FIELDS = {
264 VIEWS: { min: 0 }, 265 VIEWS: { min: 0 },
265 LIKES: { min: 0 }, 266 LIKES: { min: 0 },
266 DISLIKES: { min: 0 }, 267 DISLIKES: { min: 0 },
267 FILE_SIZE: { min: 10 }, 268 FILE_SIZE: { min: -1 },
268 URL: { min: 3, max: 2000 } // Length 269 URL: { min: 3, max: 2000 } // Length
269 }, 270 },
270 VIDEO_PLAYLISTS: { 271 VIDEO_PLAYLISTS: {
@@ -370,39 +371,41 @@ const VIDEO_LICENCES = {
370 371
371const VIDEO_LANGUAGES: { [id: string]: string } = {} 372const VIDEO_LANGUAGES: { [id: string]: string } = {}
372 373
373const VIDEO_PRIVACIES = { 374const VIDEO_PRIVACIES: { [ id in VideoPrivacy ]: string } = {
374 [VideoPrivacy.PUBLIC]: 'Public', 375 [VideoPrivacy.PUBLIC]: 'Public',
375 [VideoPrivacy.UNLISTED]: 'Unlisted', 376 [VideoPrivacy.UNLISTED]: 'Unlisted',
376 [VideoPrivacy.PRIVATE]: 'Private', 377 [VideoPrivacy.PRIVATE]: 'Private',
377 [VideoPrivacy.INTERNAL]: 'Internal' 378 [VideoPrivacy.INTERNAL]: 'Internal'
378} 379}
379 380
380const VIDEO_STATES = { 381const VIDEO_STATES: { [ id in VideoState ]: string } = {
381 [VideoState.PUBLISHED]: 'Published', 382 [VideoState.PUBLISHED]: 'Published',
382 [VideoState.TO_TRANSCODE]: 'To transcode', 383 [VideoState.TO_TRANSCODE]: 'To transcode',
383 [VideoState.TO_IMPORT]: 'To import' 384 [VideoState.TO_IMPORT]: 'To import',
385 [VideoState.WAITING_FOR_LIVE]: 'Waiting for livestream',
386 [VideoState.LIVE_ENDED]: 'Livestream ended'
384} 387}
385 388
386const VIDEO_IMPORT_STATES = { 389const VIDEO_IMPORT_STATES: { [ id in VideoImportState ]: string } = {
387 [VideoImportState.FAILED]: 'Failed', 390 [VideoImportState.FAILED]: 'Failed',
388 [VideoImportState.PENDING]: 'Pending', 391 [VideoImportState.PENDING]: 'Pending',
389 [VideoImportState.SUCCESS]: 'Success', 392 [VideoImportState.SUCCESS]: 'Success',
390 [VideoImportState.REJECTED]: 'Rejected' 393 [VideoImportState.REJECTED]: 'Rejected'
391} 394}
392 395
393const ABUSE_STATES = { 396const ABUSE_STATES: { [ id in AbuseState ]: string } = {
394 [AbuseState.PENDING]: 'Pending', 397 [AbuseState.PENDING]: 'Pending',
395 [AbuseState.REJECTED]: 'Rejected', 398 [AbuseState.REJECTED]: 'Rejected',
396 [AbuseState.ACCEPTED]: 'Accepted' 399 [AbuseState.ACCEPTED]: 'Accepted'
397} 400}
398 401
399const VIDEO_PLAYLIST_PRIVACIES = { 402const VIDEO_PLAYLIST_PRIVACIES: { [ id in VideoPlaylistPrivacy ]: string } = {
400 [VideoPlaylistPrivacy.PUBLIC]: 'Public', 403 [VideoPlaylistPrivacy.PUBLIC]: 'Public',
401 [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted', 404 [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted',
402 [VideoPlaylistPrivacy.PRIVATE]: 'Private' 405 [VideoPlaylistPrivacy.PRIVATE]: 'Private'
403} 406}
404 407
405const VIDEO_PLAYLIST_TYPES = { 408const VIDEO_PLAYLIST_TYPES: { [ id in VideoPlaylistType ]: string } = {
406 [VideoPlaylistType.REGULAR]: 'Regular', 409 [VideoPlaylistType.REGULAR]: 'Regular',
407 [VideoPlaylistType.WATCH_LATER]: 'Watch later' 410 [VideoPlaylistType.WATCH_LATER]: 'Watch later'
408} 411}
@@ -600,6 +603,17 @@ const LRU_CACHE = {
600const HLS_STREAMING_PLAYLIST_DIRECTORY = join(CONFIG.STORAGE.STREAMING_PLAYLISTS_DIR, 'hls') 603const HLS_STREAMING_PLAYLIST_DIRECTORY = join(CONFIG.STORAGE.STREAMING_PLAYLISTS_DIR, 'hls')
601const HLS_REDUNDANCY_DIRECTORY = join(CONFIG.STORAGE.REDUNDANCY_DIR, 'hls') 604const HLS_REDUNDANCY_DIRECTORY = join(CONFIG.STORAGE.REDUNDANCY_DIR, 'hls')
602 605
606const VIDEO_LIVE = {
607 EXTENSION: '.ts',
608 RTMP: {
609 CHUNK_SIZE: 60000,
610 GOP_CACHE: true,
611 PING: 60,
612 PING_TIMEOUT: 30,
613 BASE_PATH: 'live'
614 }
615}
616
603const MEMOIZE_TTL = { 617const MEMOIZE_TTL = {
604 OVERVIEWS_SAMPLE: 1000 * 3600 * 4, // 4 hours 618 OVERVIEWS_SAMPLE: 1000 * 3600 * 4, // 4 hours
605 INFO_HASH_EXISTS: 1000 * 3600 * 12 // 12 hours 619 INFO_HASH_EXISTS: 1000 * 3600 * 12 // 12 hours
@@ -622,7 +636,8 @@ const REDUNDANCY = {
622const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS) 636const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS)
623 637
624const ASSETS_PATH = { 638const ASSETS_PATH = {
625 DEFAULT_AUDIO_BACKGROUND: join(root(), 'dist', 'server', 'assets', 'default-audio-background.jpg') 639 DEFAULT_AUDIO_BACKGROUND: join(root(), 'dist', 'server', 'assets', 'default-audio-background.jpg'),
640 DEFAULT_LIVE_BACKGROUND: join(root(), 'dist', 'server', 'assets', 'default-live-background.jpg')
626} 641}
627 642
628// --------------------------------------------------------------------------- 643// ---------------------------------------------------------------------------
@@ -688,9 +703,9 @@ if (isTestInstance() === true) {
688 STATIC_MAX_AGE.SERVER = '0' 703 STATIC_MAX_AGE.SERVER = '0'
689 704
690 ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE = 2 705 ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE = 2
691 ACTIVITY_PUB.ACTOR_REFRESH_INTERVAL = 10 * 1000 // 10 seconds 706 ACTIVITY_PUB.ACTOR_REFRESH_INTERVAL = 100 * 10000 // 10 seconds
692 ACTIVITY_PUB.VIDEO_REFRESH_INTERVAL = 10 * 1000 // 10 seconds 707 ACTIVITY_PUB.VIDEO_REFRESH_INTERVAL = 100 * 10000 // 10 seconds
693 ACTIVITY_PUB.VIDEO_PLAYLIST_REFRESH_INTERVAL = 10 * 1000 // 10 seconds 708 ACTIVITY_PUB.VIDEO_PLAYLIST_REFRESH_INTERVAL = 100 * 10000 // 10 seconds
694 709
695 CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max = 100 * 1024 // 100KB 710 CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max = 100 * 1024 // 100KB
696 711
@@ -737,6 +752,7 @@ const FILES_CONTENT_HASH = {
737export { 752export {
738 WEBSERVER, 753 WEBSERVER,
739 API_VERSION, 754 API_VERSION,
755 VIDEO_LIVE,
740 PEERTUBE_VERSION, 756 PEERTUBE_VERSION,
741 LAZY_STATIC_PATHS, 757 LAZY_STATIC_PATHS,
742 SEARCH_INDEX, 758 SEARCH_INDEX,
@@ -892,10 +908,14 @@ function buildVideoMimetypeExt () {
892function updateWebserverUrls () { 908function updateWebserverUrls () {
893 WEBSERVER.URL = sanitizeUrl(CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT) 909 WEBSERVER.URL = sanitizeUrl(CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT)
894 WEBSERVER.HOST = sanitizeHost(CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT, REMOTE_SCHEME.HTTP) 910 WEBSERVER.HOST = sanitizeHost(CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT, REMOTE_SCHEME.HTTP)
895 WEBSERVER.SCHEME = CONFIG.WEBSERVER.SCHEME
896 WEBSERVER.WS = CONFIG.WEBSERVER.WS 911 WEBSERVER.WS = CONFIG.WEBSERVER.WS
912
913 WEBSERVER.SCHEME = CONFIG.WEBSERVER.SCHEME
897 WEBSERVER.HOSTNAME = CONFIG.WEBSERVER.HOSTNAME 914 WEBSERVER.HOSTNAME = CONFIG.WEBSERVER.HOSTNAME
898 WEBSERVER.PORT = CONFIG.WEBSERVER.PORT 915 WEBSERVER.PORT = CONFIG.WEBSERVER.PORT
916 WEBSERVER.PORT = CONFIG.WEBSERVER.PORT
917
918 WEBSERVER.RTMP_URL = 'rtmp://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.LIVE.RTMP.PORT + '/' + VIDEO_LIVE.RTMP.BASE_PATH
899} 919}
900 920
901function updateWebserverConfig () { 921function updateWebserverConfig () {
diff --git a/server/initializers/database.ts b/server/initializers/database.ts
index a20cdacc3..128ed5b75 100644
--- a/server/initializers/database.ts
+++ b/server/initializers/database.ts
@@ -1,11 +1,11 @@
1import { QueryTypes, Transaction } from 'sequelize' 1import { QueryTypes, Transaction } from 'sequelize'
2import { Sequelize as SequelizeTypescript } from 'sequelize-typescript' 2import { Sequelize as SequelizeTypescript } from 'sequelize-typescript'
3import { AbuseModel } from '@server/models/abuse/abuse'
4import { AbuseMessageModel } from '@server/models/abuse/abuse-message'
5import { VideoAbuseModel } from '@server/models/abuse/video-abuse'
6import { VideoCommentAbuseModel } from '@server/models/abuse/video-comment-abuse'
7import { isTestInstance } from '../helpers/core-utils' 3import { isTestInstance } from '../helpers/core-utils'
8import { logger } from '../helpers/logger' 4import { logger } from '../helpers/logger'
5import { AbuseModel } from '../models/abuse/abuse'
6import { AbuseMessageModel } from '../models/abuse/abuse-message'
7import { VideoAbuseModel } from '../models/abuse/video-abuse'
8import { VideoCommentAbuseModel } from '../models/abuse/video-comment-abuse'
9import { AccountModel } from '../models/account/account' 9import { AccountModel } from '../models/account/account'
10import { AccountBlocklistModel } from '../models/account/account-blocklist' 10import { AccountBlocklistModel } from '../models/account/account-blocklist'
11import { AccountVideoRateModel } from '../models/account/account-video-rate' 11import { AccountVideoRateModel } from '../models/account/account-video-rate'
@@ -34,6 +34,7 @@ import { VideoChannelModel } from '../models/video/video-channel'
34import { VideoCommentModel } from '../models/video/video-comment' 34import { VideoCommentModel } from '../models/video/video-comment'
35import { VideoFileModel } from '../models/video/video-file' 35import { VideoFileModel } from '../models/video/video-file'
36import { VideoImportModel } from '../models/video/video-import' 36import { VideoImportModel } from '../models/video/video-import'
37import { VideoLiveModel } from '../models/video/video-live'
37import { VideoPlaylistModel } from '../models/video/video-playlist' 38import { VideoPlaylistModel } from '../models/video/video-playlist'
38import { VideoPlaylistElementModel } from '../models/video/video-playlist-element' 39import { VideoPlaylistElementModel } from '../models/video/video-playlist-element'
39import { VideoShareModel } from '../models/video/video-share' 40import { VideoShareModel } from '../models/video/video-share'
@@ -118,6 +119,7 @@ async function initDatabaseModels (silent: boolean) {
118 VideoViewModel, 119 VideoViewModel,
119 VideoRedundancyModel, 120 VideoRedundancyModel,
120 UserVideoHistoryModel, 121 UserVideoHistoryModel,
122 VideoLiveModel,
121 AccountBlocklistModel, 123 AccountBlocklistModel,
122 ServerBlocklistModel, 124 ServerBlocklistModel,
123 UserNotificationModel, 125 UserNotificationModel,
diff --git a/server/initializers/migrations/0535-video-live.ts b/server/initializers/migrations/0535-video-live.ts
new file mode 100644
index 000000000..35523efc4
--- /dev/null
+++ b/server/initializers/migrations/0535-video-live.ts
@@ -0,0 +1,39 @@
1import * as Sequelize from 'sequelize'
2
3async function up (utils: {
4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize
7}): Promise<void> {
8 {
9 const query = `
10 CREATE TABLE IF NOT EXISTS "videoLive" (
11 "id" SERIAL ,
12 "streamKey" VARCHAR(255) NOT NULL,
13 "videoId" INTEGER NOT NULL REFERENCES "video" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
14 "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL,
15 "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL,
16 PRIMARY KEY ("id")
17 );
18 `
19
20 await utils.sequelize.query(query)
21 }
22
23 {
24 await utils.queryInterface.addColumn('video', 'isLive', {
25 type: Sequelize.BOOLEAN,
26 defaultValue: false,
27 allowNull: false
28 })
29 }
30}
31
32function down (options) {
33 throw new Error('Not implemented.')
34}
35
36export {
37 up,
38 down
39}
diff --git a/server/initializers/migrations/0540-video-file-infohash.ts b/server/initializers/migrations/0540-video-file-infohash.ts
new file mode 100644
index 000000000..550178dab
--- /dev/null
+++ b/server/initializers/migrations/0540-video-file-infohash.ts
@@ -0,0 +1,26 @@
1import * as Sequelize from 'sequelize'
2
3async function up (utils: {
4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize
7}): Promise<void> {
8 {
9 const data = {
10 type: Sequelize.STRING,
11 defaultValue: null,
12 allowNull: true
13 }
14
15 await utils.queryInterface.changeColumn('videoFile', 'infoHash', data)
16 }
17}
18
19function down (options) {
20 throw new Error('Not implemented.')
21}
22
23export {
24 up,
25 down
26}