diff options
author | Chocobozzz <me@florianbigard.com> | 2023-06-01 14:51:16 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2023-06-29 10:16:55 +0200 |
commit | d8f39b126d9fe4bec1c12fb213548cc6edc87867 (patch) | |
tree | 7f0f1cb23165cf4dd789b2d78b1fef7ee116f647 /shared | |
parent | 1fb7d094229acdc190c3f7551b43ac5445814dee (diff) | |
download | PeerTube-d8f39b126d9fe4bec1c12fb213548cc6edc87867.tar.gz PeerTube-d8f39b126d9fe4bec1c12fb213548cc6edc87867.tar.zst PeerTube-d8f39b126d9fe4bec1c12fb213548cc6edc87867.zip |
Add storyboard support
Diffstat (limited to 'shared')
-rw-r--r-- | shared/ffmpeg/ffmpeg-images.ts | 37 | ||||
-rw-r--r-- | shared/models/activitypub/objects/index.ts | 2 | ||||
-rw-r--r-- | shared/models/activitypub/objects/video-object.ts (renamed from shared/models/activitypub/objects/video-torrent-object.ts) | 16 | ||||
-rw-r--r-- | shared/models/server/custom-config.model.ts | 4 | ||||
-rw-r--r-- | shared/models/server/job.model.ts | 8 | ||||
-rw-r--r-- | shared/models/videos/index.ts | 1 | ||||
-rw-r--r-- | shared/models/videos/storyboard.model.ts | 11 | ||||
-rw-r--r-- | shared/server-commands/server/config-command.ts | 7 | ||||
-rw-r--r-- | shared/server-commands/server/jobs.ts | 15 | ||||
-rw-r--r-- | shared/server-commands/server/server.ts | 5 | ||||
-rw-r--r-- | shared/server-commands/videos/index.ts | 1 | ||||
-rw-r--r-- | shared/server-commands/videos/storyboard-command.ts | 19 |
12 files changed, 124 insertions, 2 deletions
diff --git a/shared/ffmpeg/ffmpeg-images.ts b/shared/ffmpeg/ffmpeg-images.ts index 2db63bd8b..27305382c 100644 --- a/shared/ffmpeg/ffmpeg-images.ts +++ b/shared/ffmpeg/ffmpeg-images.ts | |||
@@ -56,4 +56,41 @@ export class FFmpegImage { | |||
56 | .thumbnail(thumbnailOptions) | 56 | .thumbnail(thumbnailOptions) |
57 | }) | 57 | }) |
58 | } | 58 | } |
59 | |||
60 | async generateStoryboardFromVideo (options: { | ||
61 | path: string | ||
62 | destination: string | ||
63 | |||
64 | sprites: { | ||
65 | size: { | ||
66 | width: number | ||
67 | height: number | ||
68 | } | ||
69 | |||
70 | count: { | ||
71 | width: number | ||
72 | height: number | ||
73 | } | ||
74 | |||
75 | duration: number | ||
76 | } | ||
77 | }) { | ||
78 | const { path, destination, sprites } = options | ||
79 | |||
80 | const command = this.commandWrapper.buildCommand(path) | ||
81 | |||
82 | const filter = [ | ||
83 | `setpts=N/round(FRAME_RATE)/TB`, | ||
84 | `select='not(mod(t,${options.sprites.duration}))'`, | ||
85 | `scale=${sprites.size.width}:${sprites.size.height}`, | ||
86 | `tile=layout=${sprites.count.width}x${sprites.count.height}` | ||
87 | ].join(',') | ||
88 | |||
89 | command.outputOption('-filter_complex', filter) | ||
90 | command.outputOption('-frames:v', '1') | ||
91 | command.outputOption('-q:v', '2') | ||
92 | command.output(destination) | ||
93 | |||
94 | return this.commandWrapper.runCommand() | ||
95 | } | ||
59 | } | 96 | } |
diff --git a/shared/models/activitypub/objects/index.ts b/shared/models/activitypub/objects/index.ts index 9aa3c462c..a2e040b32 100644 --- a/shared/models/activitypub/objects/index.ts +++ b/shared/models/activitypub/objects/index.ts | |||
@@ -6,5 +6,5 @@ export * from './object.model' | |||
6 | export * from './playlist-element-object' | 6 | export * from './playlist-element-object' |
7 | export * from './playlist-object' | 7 | export * from './playlist-object' |
8 | export * from './video-comment-object' | 8 | export * from './video-comment-object' |
9 | export * from './video-torrent-object' | 9 | export * from './video-object' |
10 | export * from './watch-action-object' | 10 | export * from './watch-action-object' |
diff --git a/shared/models/activitypub/objects/video-torrent-object.ts b/shared/models/activitypub/objects/video-object.ts index 23d54bdbd..a252a2df0 100644 --- a/shared/models/activitypub/objects/video-torrent-object.ts +++ b/shared/models/activitypub/objects/video-object.ts | |||
@@ -51,6 +51,22 @@ export interface VideoObject { | |||
51 | 51 | ||
52 | attributedTo: ActivityPubAttributedTo[] | 52 | attributedTo: ActivityPubAttributedTo[] |
53 | 53 | ||
54 | preview?: ActivityPubStoryboard[] | ||
55 | |||
54 | to?: string[] | 56 | to?: string[] |
55 | cc?: string[] | 57 | cc?: string[] |
56 | } | 58 | } |
59 | |||
60 | export interface ActivityPubStoryboard { | ||
61 | type: 'Image' | ||
62 | rel: [ 'storyboard' ] | ||
63 | url: { | ||
64 | href: string | ||
65 | mediaType: string | ||
66 | width: number | ||
67 | height: number | ||
68 | tileWidth: number | ||
69 | tileHeight: number | ||
70 | tileDuration: string | ||
71 | }[] | ||
72 | } | ||
diff --git a/shared/models/server/custom-config.model.ts b/shared/models/server/custom-config.model.ts index 4202589f3..1012312f3 100644 --- a/shared/models/server/custom-config.model.ts +++ b/shared/models/server/custom-config.model.ts | |||
@@ -78,6 +78,10 @@ export interface CustomConfig { | |||
78 | torrents: { | 78 | torrents: { |
79 | size: number | 79 | size: number |
80 | } | 80 | } |
81 | |||
82 | storyboards: { | ||
83 | size: number | ||
84 | } | ||
81 | } | 85 | } |
82 | 86 | ||
83 | signup: { | 87 | signup: { |
diff --git a/shared/models/server/job.model.ts b/shared/models/server/job.model.ts index 22ecee324..9c40079fb 100644 --- a/shared/models/server/job.model.ts +++ b/shared/models/server/job.model.ts | |||
@@ -30,6 +30,7 @@ export type JobType = | |||
30 | | 'video-studio-edition' | 30 | | 'video-studio-edition' |
31 | | 'video-transcoding' | 31 | | 'video-transcoding' |
32 | | 'videos-views-stats' | 32 | | 'videos-views-stats' |
33 | | 'generate-video-storyboard' | ||
33 | 34 | ||
34 | export interface Job { | 35 | export interface Job { |
35 | id: number | string | 36 | id: number | string |
@@ -294,3 +295,10 @@ export interface TranscodingJobBuilderPayload { | |||
294 | priority?: number | 295 | priority?: number |
295 | }[][] | 296 | }[][] |
296 | } | 297 | } |
298 | |||
299 | // --------------------------------------------------------------------------- | ||
300 | |||
301 | export interface GenerateStoryboardPayload { | ||
302 | videoUUID: string | ||
303 | federate: boolean | ||
304 | } | ||
diff --git a/shared/models/videos/index.ts b/shared/models/videos/index.ts index 80be1854b..b3ce6ad3f 100644 --- a/shared/models/videos/index.ts +++ b/shared/models/videos/index.ts | |||
@@ -15,6 +15,7 @@ export * from './channel-sync' | |||
15 | 15 | ||
16 | export * from './nsfw-policy.type' | 16 | export * from './nsfw-policy.type' |
17 | 17 | ||
18 | export * from './storyboard.model' | ||
18 | export * from './thumbnail.type' | 19 | export * from './thumbnail.type' |
19 | 20 | ||
20 | export * from './video-constant.model' | 21 | export * from './video-constant.model' |
diff --git a/shared/models/videos/storyboard.model.ts b/shared/models/videos/storyboard.model.ts new file mode 100644 index 000000000..c92c81f09 --- /dev/null +++ b/shared/models/videos/storyboard.model.ts | |||
@@ -0,0 +1,11 @@ | |||
1 | export interface Storyboard { | ||
2 | storyboardPath: string | ||
3 | |||
4 | totalHeight: number | ||
5 | totalWidth: number | ||
6 | |||
7 | spriteHeight: number | ||
8 | spriteWidth: number | ||
9 | |||
10 | spriteDuration: number | ||
11 | } | ||
diff --git a/shared/server-commands/server/config-command.ts b/shared/server-commands/server/config-command.ts index b94bd2625..114db8091 100644 --- a/shared/server-commands/server/config-command.ts +++ b/shared/server-commands/server/config-command.ts | |||
@@ -159,6 +159,10 @@ export class ConfigCommand extends AbstractCommand { | |||
159 | newConfig: { | 159 | newConfig: { |
160 | transcoding: { | 160 | transcoding: { |
161 | enabled: true, | 161 | enabled: true, |
162 | |||
163 | allowAudioFiles: true, | ||
164 | allowAdditionalExtensions: true, | ||
165 | |||
162 | resolutions: { | 166 | resolutions: { |
163 | ...ConfigCommand.getCustomConfigResolutions(false), | 167 | ...ConfigCommand.getCustomConfigResolutions(false), |
164 | 168 | ||
@@ -368,6 +372,9 @@ export class ConfigCommand extends AbstractCommand { | |||
368 | }, | 372 | }, |
369 | torrents: { | 373 | torrents: { |
370 | size: 4 | 374 | size: 4 |
375 | }, | ||
376 | storyboards: { | ||
377 | size: 5 | ||
371 | } | 378 | } |
372 | }, | 379 | }, |
373 | signup: { | 380 | signup: { |
diff --git a/shared/server-commands/server/jobs.ts b/shared/server-commands/server/jobs.ts index ff3098063..8f131fba4 100644 --- a/shared/server-commands/server/jobs.ts +++ b/shared/server-commands/server/jobs.ts | |||
@@ -33,6 +33,8 @@ async function waitJobs ( | |||
33 | 33 | ||
34 | // Check if each server has pending request | 34 | // Check if each server has pending request |
35 | for (const server of servers) { | 35 | for (const server of servers) { |
36 | if (process.env.DEBUG) console.log('Checking ' + server.url) | ||
37 | |||
36 | for (const state of states) { | 38 | for (const state of states) { |
37 | 39 | ||
38 | const jobPromise = server.jobs.list({ | 40 | const jobPromise = server.jobs.list({ |
@@ -45,6 +47,10 @@ async function waitJobs ( | |||
45 | .then(jobs => { | 47 | .then(jobs => { |
46 | if (jobs.length !== 0) { | 48 | if (jobs.length !== 0) { |
47 | pendingRequests = true | 49 | pendingRequests = true |
50 | |||
51 | if (process.env.DEBUG) { | ||
52 | console.log(jobs) | ||
53 | } | ||
48 | } | 54 | } |
49 | }) | 55 | }) |
50 | 56 | ||
@@ -55,6 +61,10 @@ async function waitJobs ( | |||
55 | .then(obj => { | 61 | .then(obj => { |
56 | if (obj.activityPubMessagesWaiting !== 0) { | 62 | if (obj.activityPubMessagesWaiting !== 0) { |
57 | pendingRequests = true | 63 | pendingRequests = true |
64 | |||
65 | if (process.env.DEBUG) { | ||
66 | console.log('AP messages waiting: ' + obj.activityPubMessagesWaiting) | ||
67 | } | ||
58 | } | 68 | } |
59 | }) | 69 | }) |
60 | tasks.push(debugPromise) | 70 | tasks.push(debugPromise) |
@@ -65,12 +75,15 @@ async function waitJobs ( | |||
65 | for (const job of data) { | 75 | for (const job of data) { |
66 | if (job.state.id !== RunnerJobState.COMPLETED) { | 76 | if (job.state.id !== RunnerJobState.COMPLETED) { |
67 | pendingRequests = true | 77 | pendingRequests = true |
78 | |||
79 | if (process.env.DEBUG) { | ||
80 | console.log(job) | ||
81 | } | ||
68 | } | 82 | } |
69 | } | 83 | } |
70 | }) | 84 | }) |
71 | tasks.push(runnerJobsPromise) | 85 | tasks.push(runnerJobsPromise) |
72 | } | 86 | } |
73 | |||
74 | } | 87 | } |
75 | 88 | ||
76 | return tasks | 89 | return tasks |
diff --git a/shared/server-commands/server/server.ts b/shared/server-commands/server/server.ts index 0911e22b0..6aa4296b0 100644 --- a/shared/server-commands/server/server.ts +++ b/shared/server-commands/server/server.ts | |||
@@ -35,6 +35,7 @@ import { | |||
35 | VideoPasswordsCommand, | 35 | VideoPasswordsCommand, |
36 | PlaylistsCommand, | 36 | PlaylistsCommand, |
37 | ServicesCommand, | 37 | ServicesCommand, |
38 | StoryboardCommand, | ||
38 | StreamingPlaylistsCommand, | 39 | StreamingPlaylistsCommand, |
39 | VideosCommand, | 40 | VideosCommand, |
40 | VideoStudioCommand, | 41 | VideoStudioCommand, |
@@ -149,6 +150,8 @@ export class PeerTubeServer { | |||
149 | registrations?: RegistrationsCommand | 150 | registrations?: RegistrationsCommand |
150 | videoPasswords?: VideoPasswordsCommand | 151 | videoPasswords?: VideoPasswordsCommand |
151 | 152 | ||
153 | storyboard?: StoryboardCommand | ||
154 | |||
152 | runners?: RunnersCommand | 155 | runners?: RunnersCommand |
153 | runnerRegistrationTokens?: RunnerRegistrationTokensCommand | 156 | runnerRegistrationTokens?: RunnerRegistrationTokensCommand |
154 | runnerJobs?: RunnerJobsCommand | 157 | runnerJobs?: RunnerJobsCommand |
@@ -436,6 +439,8 @@ export class PeerTubeServer { | |||
436 | this.videoToken = new VideoTokenCommand(this) | 439 | this.videoToken = new VideoTokenCommand(this) |
437 | this.registrations = new RegistrationsCommand(this) | 440 | this.registrations = new RegistrationsCommand(this) |
438 | 441 | ||
442 | this.storyboard = new StoryboardCommand(this) | ||
443 | |||
439 | this.runners = new RunnersCommand(this) | 444 | this.runners = new RunnersCommand(this) |
440 | this.runnerRegistrationTokens = new RunnerRegistrationTokensCommand(this) | 445 | this.runnerRegistrationTokens = new RunnerRegistrationTokensCommand(this) |
441 | this.runnerJobs = new RunnerJobsCommand(this) | 446 | this.runnerJobs = new RunnerJobsCommand(this) |
diff --git a/shared/server-commands/videos/index.ts b/shared/server-commands/videos/index.ts index da36b5b6b..106d80af0 100644 --- a/shared/server-commands/videos/index.ts +++ b/shared/server-commands/videos/index.ts | |||
@@ -11,6 +11,7 @@ export * from './live-command' | |||
11 | export * from './live' | 11 | export * from './live' |
12 | export * from './playlists-command' | 12 | export * from './playlists-command' |
13 | export * from './services-command' | 13 | export * from './services-command' |
14 | export * from './storyboard-command' | ||
14 | export * from './streaming-playlists-command' | 15 | export * from './streaming-playlists-command' |
15 | export * from './comments-command' | 16 | export * from './comments-command' |
16 | export * from './video-studio-command' | 17 | export * from './video-studio-command' |
diff --git a/shared/server-commands/videos/storyboard-command.ts b/shared/server-commands/videos/storyboard-command.ts new file mode 100644 index 000000000..06d90fc12 --- /dev/null +++ b/shared/server-commands/videos/storyboard-command.ts | |||
@@ -0,0 +1,19 @@ | |||
1 | import { HttpStatusCode, Storyboard } from '@shared/models' | ||
2 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | ||
3 | |||
4 | export class StoryboardCommand extends AbstractCommand { | ||
5 | |||
6 | list (options: OverrideCommandOptions & { | ||
7 | id: number | string | ||
8 | }) { | ||
9 | const path = '/api/v1/videos/' + options.id + '/storyboards' | ||
10 | |||
11 | return this.getRequestBody<{ storyboards: Storyboard[] }>({ | ||
12 | ...options, | ||
13 | |||
14 | path, | ||
15 | implicitToken: true, | ||
16 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
17 | }) | ||
18 | } | ||
19 | } | ||