From b6b1aaa56f5eb0b5e5b7366e08a698d3a6f917cd Mon Sep 17 00:00:00 2001
From: Chocobozzz <me@florianbigard.com>
Date: Tue, 27 Feb 2024 11:18:56 +0100
Subject: [PATCH] Add video aspect ratio in server

---
 .../shared/shared-main/video/video.model.ts   |   4 +
 packages/core-utils/src/videos/bitrate.ts     |   7 +-
 packages/core-utils/src/videos/common.ts      |  15 ++--
 packages/ffmpeg/src/ffprobe.ts                |   4 +-
 .../src/activitypub/objects/common-objects.ts |  10 ++-
 .../src/activitypub/objects/video-object.ts   |   2 +
 .../src/videos/file/video-file.model.ts       |   3 +
 packages/models/src/videos/video.model.ts     |   2 +
 .../fixtures/video_import_preview_yt_dlp.jpg  | Bin 15844 -> 49065 bytes
 packages/tests/src/api/live/live.ts           |   3 +
 .../tests/src/api/redundancy/redundancy.ts    |   4 +-
 packages/tests/src/api/server/follows.ts      |   2 +
 packages/tests/src/api/server/handle-down.ts  |   2 +
 packages/tests/src/api/server/tracker.ts      |   6 +-
 packages/tests/src/api/users/user-import.ts   |   4 +
 .../tests/src/api/videos/multiple-servers.ts  |  24 ++++++
 .../tests/src/api/videos/single-server.ts     |   4 +
 packages/tests/src/api/videos/video-files.ts  |   7 +-
 .../api/videos/video-static-file-privacy.ts   |   7 +-
 .../tests/src/server-helpers/core-utils.ts    |  20 ++++-
 packages/tests/src/shared/checks.ts           |  10 ++-
 packages/tests/src/shared/live.ts             |   2 +
 .../tests/src/shared/streaming-playlists.ts   |   3 +
 packages/tests/src/shared/videos.ts           |  14 +++-
 packages/tests/src/shared/webtorrent.ts       |   9 ++
 server/core/controllers/api/videos/source.ts  |   2 +
 server/core/helpers/activity-pub-utils.ts     |   4 +
 server/core/initializers/constants.ts         |   2 +-
 .../migrations/0825-video-ratio.ts            |  43 ++++++++++
 .../shared/object-to-model-attributes.ts      |   5 +-
 server/core/lib/activitypub/videos/updater.ts |   1 +
 .../job-queue/handlers/generate-storyboard.ts |   4 +-
 .../job-queue/handlers/video-file-import.ts   |  25 ++----
 .../lib/job-queue/handlers/video-import.ts    |  54 ++++--------
 .../job-queue/handlers/video-live-ending.ts   |   1 +
 server/core/lib/live/live-manager.ts          |  13 ++-
 server/core/lib/local-video-creator.ts        |   3 +
 .../job-handlers/shared/vod-helpers.ts        |  38 ++-------
 ...vod-audio-merge-transcoding-job-handler.ts |   8 +-
 .../vod-hls-transcoding-job-handler.ts        |  21 +----
 .../vod-web-video-transcoding-job-handler.ts  |   2 +-
 .../core/lib/transcoding/hls-transcoding.ts   |  51 +++++------
 .../core/lib/transcoding/web-transcoding.ts   |  79 +++++++-----------
 server/core/lib/video-file.ts                 |   5 +-
 server/core/lib/video-studio.ts               |   2 +
 server/core/models/server/plugin.ts           |   2 +
 .../formatter/video-activity-pub-format.ts    |  13 ++-
 .../video/formatter/video-api-format.ts       |   5 ++
 .../video/shared/video-table-attributes.ts    |   3 +
 server/core/models/video/video-file.ts        |  11 ++-
 server/core/models/video/video.ts             |   4 +
 support/doc/api/openapi.yaml                  |  13 ++-
 52 files changed, 345 insertions(+), 237 deletions(-)
 create mode 100644 server/core/initializers/migrations/0825-video-ratio.ts

diff --git a/client/src/app/shared/shared-main/video/video.model.ts b/client/src/app/shared/shared-main/video/video.model.ts
index 81a7cd3ee..99ea394ca 100644
--- a/client/src/app/shared/shared-main/video/video.model.ts
+++ b/client/src/app/shared/shared-main/video/video.model.ts
@@ -50,6 +50,8 @@ export class Video implements VideoServerModel {
   thumbnailPath: string
   thumbnailUrl: string
 
+  aspectRatio: number
+
   isLive: boolean
 
   previewPath: string
@@ -197,6 +199,8 @@ export class Video implements VideoServerModel {
     this.originInstanceUrl = 'https://' + this.originInstanceHost
 
     this.pluginData = hash.pluginData
+
+    this.aspectRatio = hash.aspectRatio
   }
 
   isVideoNSFWForUser (user: User, serverConfig: HTMLServerConfig) {
diff --git a/packages/core-utils/src/videos/bitrate.ts b/packages/core-utils/src/videos/bitrate.ts
index b28eaf460..40dcd6bdf 100644
--- a/packages/core-utils/src/videos/bitrate.ts
+++ b/packages/core-utils/src/videos/bitrate.ts
@@ -103,9 +103,14 @@ function calculateBitrate (options: {
     VideoResolution.H_NOVIDEO
   ]
 
+  const size1 = resolution
+  const size2 = ratio < 1 && ratio > 0
+    ? resolution / ratio // Portrait mode
+    : resolution * ratio
+
   for (const toTestResolution of resolutionsOrder) {
     if (toTestResolution <= resolution) {
-      return Math.floor(resolution * resolution * ratio * fps * bitPerPixel[toTestResolution])
+      return Math.floor(size1 * size2 * fps * bitPerPixel[toTestResolution])
     }
   }
 
diff --git a/packages/core-utils/src/videos/common.ts b/packages/core-utils/src/videos/common.ts
index 47564fb2a..64e66094c 100644
--- a/packages/core-utils/src/videos/common.ts
+++ b/packages/core-utils/src/videos/common.ts
@@ -1,10 +1,10 @@
 import { VideoDetails, VideoPrivacy, VideoStreamingPlaylistType } from '@peertube/peertube-models'
 
-function getAllPrivacies () {
+export function getAllPrivacies () {
   return [ VideoPrivacy.PUBLIC, VideoPrivacy.INTERNAL, VideoPrivacy.PRIVATE, VideoPrivacy.UNLISTED, VideoPrivacy.PASSWORD_PROTECTED ]
 }
 
-function getAllFiles (video: Partial<Pick<VideoDetails, 'files' | 'streamingPlaylists'>>) {
+export function getAllFiles (video: Partial<Pick<VideoDetails, 'files' | 'streamingPlaylists'>>) {
   const files = video.files
 
   const hls = getHLS(video)
@@ -13,12 +13,13 @@ function getAllFiles (video: Partial<Pick<VideoDetails, 'files' | 'streamingPlay
   return files
 }
 
-function getHLS (video: Partial<Pick<VideoDetails, 'streamingPlaylists'>>) {
+export function getHLS (video: Partial<Pick<VideoDetails, 'streamingPlaylists'>>) {
   return video.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS)
 }
 
-export {
-  getAllPrivacies,
-  getAllFiles,
-  getHLS
+export function buildAspectRatio (options: { width: number, height: number }) {
+  const { width, height } = options
+  if (!width || !height) return null
+
+  return Math.round((width / height) * 10000) / 10000 // 4 decimals precision
 }
diff --git a/packages/ffmpeg/src/ffprobe.ts b/packages/ffmpeg/src/ffprobe.ts
index 657676972..d86ba3d12 100644
--- a/packages/ffmpeg/src/ffprobe.ts
+++ b/packages/ffmpeg/src/ffprobe.ts
@@ -1,5 +1,5 @@
 import ffmpeg, { FfprobeData } from 'fluent-ffmpeg'
-import { forceNumber } from '@peertube/peertube-core-utils'
+import { buildAspectRatio, forceNumber } from '@peertube/peertube-core-utils'
 import { VideoResolution } from '@peertube/peertube-models'
 
 /**
@@ -123,7 +123,7 @@ async function getVideoStreamDimensionsInfo (path: string, existingProbe?: Ffpro
   return {
     width: videoStream.width,
     height: videoStream.height,
-    ratio: Math.max(videoStream.height, videoStream.width) / Math.min(videoStream.height, videoStream.width),
+    ratio: buildAspectRatio({ width: videoStream.width, height: videoStream.height }),
     resolution: Math.min(videoStream.height, videoStream.width),
     isPortraitMode: videoStream.height > videoStream.width
   }
diff --git a/packages/models/src/activitypub/objects/common-objects.ts b/packages/models/src/activitypub/objects/common-objects.ts
index df5dcb56f..6c8fca2ff 100644
--- a/packages/models/src/activitypub/objects/common-objects.ts
+++ b/packages/models/src/activitypub/objects/common-objects.ts
@@ -10,8 +10,8 @@ export interface ActivityIconObject {
   type: 'Image'
   url: string
   mediaType: string
-  width?: number
-  height?: number
+  width: number
+  height: number | null
 }
 
 export type ActivityVideoUrlObject = {
@@ -19,6 +19,7 @@ export type ActivityVideoUrlObject = {
   mediaType: 'video/mp4' | 'video/webm' | 'video/ogg' | 'audio/mp4'
   href: string
   height: number
+  width: number | null
   size: number
   fps: number
 }
@@ -35,6 +36,7 @@ export type ActivityVideoFileMetadataUrlObject = {
   rel: [ 'metadata', any ]
   mediaType: 'application/json'
   height: number
+  width: number | null
   href: string
   fps: number
 }
@@ -63,6 +65,8 @@ export type ActivityBitTorrentUrlObject = {
   mediaType: 'application/x-bittorrent' | 'application/x-bittorrent;x-scheme-handler/magnet'
   href: string
   height: number
+  width: number | null
+  fps: number | null
 }
 
 export type ActivityMagnetUrlObject = {
@@ -70,6 +74,8 @@ export type ActivityMagnetUrlObject = {
   mediaType: 'application/x-bittorrent;x-scheme-handler/magnet'
   href: string
   height: number
+  width: number | null
+  fps: number | null
 }
 
 export type ActivityHtmlUrlObject = {
diff --git a/packages/models/src/activitypub/objects/video-object.ts b/packages/models/src/activitypub/objects/video-object.ts
index 1861454a8..16dbe1aab 100644
--- a/packages/models/src/activitypub/objects/video-object.ts
+++ b/packages/models/src/activitypub/objects/video-object.ts
@@ -44,6 +44,8 @@ export interface VideoObject {
 
   support: string
 
+  aspectRatio: number
+
   icon: ActivityIconObject[]
 
   url: ActivityUrlObject[]
diff --git a/packages/models/src/videos/file/video-file.model.ts b/packages/models/src/videos/file/video-file.model.ts
index 2ed1ac4be..9745eb752 100644
--- a/packages/models/src/videos/file/video-file.model.ts
+++ b/packages/models/src/videos/file/video-file.model.ts
@@ -7,6 +7,9 @@ export interface VideoFile {
   resolution: VideoConstant<number>
   size: number // Bytes
 
+  width?: number
+  height?: number
+
   torrentUrl: string
   torrentDownloadUrl: string
 
diff --git a/packages/models/src/videos/video.model.ts b/packages/models/src/videos/video.model.ts
index a750e220d..4e78b267e 100644
--- a/packages/models/src/videos/video.model.ts
+++ b/packages/models/src/videos/video.model.ts
@@ -29,6 +29,8 @@ export interface Video extends Partial<VideoAdditionalAttributes> {
   isLocal: boolean
   name: string
 
+  aspectRatio: number | null
+
   isLive: boolean
 
   thumbnailPath: string
diff --git a/packages/tests/fixtures/video_import_preview_yt_dlp.jpg b/packages/tests/fixtures/video_import_preview_yt_dlp.jpg
index 9e8833bf9424964a91d8ce38718f780ca016a057..029fb9ee8ebfc6f7c2baa078aed0a107b3a5d9e2 100644
GIT binary patch
literal 49065
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%0D6`T0pLT{gl0^`U
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

literal 15844
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
TZU6WF4fp@2KMxc9`T0KpI%<R9

diff --git a/packages/tests/src/api/live/live.ts b/packages/tests/src/api/live/live.ts
index ac839c872..ea05ccc3c 100644
--- a/packages/tests/src/api/live/live.ts
+++ b/packages/tests/src/api/live/live.ts
@@ -115,6 +115,8 @@ describe('Test live', function () {
 
         expect(video.isLive).to.be.true
 
+        expect(video.aspectRatio).to.not.exist
+
         expect(video.nsfw).to.be.false
         expect(video.waitTranscoding).to.be.false
         expect(video.name).to.equal('my super live')
@@ -552,6 +554,7 @@ describe('Test live', function () {
 
         expect(video.state.id).to.equal(VideoState.PUBLISHED)
         expect(video.duration).to.be.greaterThan(1)
+        expect(video.aspectRatio).to.equal(1.7778)
         expect(video.files).to.have.lengthOf(0)
 
         const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS)
diff --git a/packages/tests/src/api/redundancy/redundancy.ts b/packages/tests/src/api/redundancy/redundancy.ts
index 69afae037..2540abb40 100644
--- a/packages/tests/src/api/redundancy/redundancy.ts
+++ b/packages/tests/src/api/redundancy/redundancy.ts
@@ -2,7 +2,6 @@
 
 import { expect } from 'chai'
 import { readdir } from 'fs/promises'
-import { decode as magnetUriDecode } from 'magnet-uri'
 import { basename, join } from 'path'
 import { wait } from '@peertube/peertube-core-utils'
 import {
@@ -25,12 +24,13 @@ import {
 } from '@peertube/peertube-server-commands'
 import { checkSegmentHash } from '@tests/shared/streaming-playlists.js'
 import { checkVideoFilesWereRemoved, saveVideoInServers } from '@tests/shared/videos.js'
+import { magnetUriDecode } from '@tests/shared/webtorrent.js'
 
 let servers: PeerTubeServer[] = []
 let video1Server2: VideoDetails
 
 async function checkMagnetWebseeds (file: VideoFile, baseWebseeds: string[], server: PeerTubeServer) {
-  const parsed = magnetUriDecode(file.magnetUri)
+  const parsed = await magnetUriDecode(file.magnetUri)
 
   for (const ws of baseWebseeds) {
     const found = parsed.urlList.find(url => url === `${ws}${basename(file.fileUrl)}`)
diff --git a/packages/tests/src/api/server/follows.ts b/packages/tests/src/api/server/follows.ts
index 56eb86e87..448f28d62 100644
--- a/packages/tests/src/api/server/follows.ts
+++ b/packages/tests/src/api/server/follows.ts
@@ -479,6 +479,8 @@ describe('Test follows', function () {
           files: [
             {
               resolution: 720,
+              width: 1280,
+              height: 720,
               size: 218910
             }
           ]
diff --git a/packages/tests/src/api/server/handle-down.ts b/packages/tests/src/api/server/handle-down.ts
index e5f0796a1..474048037 100644
--- a/packages/tests/src/api/server/handle-down.ts
+++ b/packages/tests/src/api/server/handle-down.ts
@@ -69,6 +69,8 @@ describe('Test handle downs', function () {
     fixture: 'video_short1.webm',
     files: [
       {
+        height: 720,
+        width: 1280,
         resolution: 720,
         size: 572456
       }
diff --git a/packages/tests/src/api/server/tracker.ts b/packages/tests/src/api/server/tracker.ts
index 4df4e4613..159b49c49 100644
--- a/packages/tests/src/api/server/tracker.ts
+++ b/packages/tests/src/api/server/tracker.ts
@@ -1,6 +1,5 @@
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await,@typescript-eslint/no-floating-promises */
 
-import { decode as magnetUriDecode, encode as magnetUriEncode } from 'magnet-uri'
 import WebTorrent from 'webtorrent'
 import {
   cleanupTests,
@@ -9,6 +8,7 @@ import {
   PeerTubeServer,
   setAccessTokensToServers
 } from '@peertube/peertube-server-commands'
+import { magnetUriDecode, magnetUriEncode } from '@tests/shared/webtorrent.js'
 
 describe('Test tracker', function () {
   let server: PeerTubeServer
@@ -25,10 +25,10 @@ describe('Test tracker', function () {
       const video = await server.videos.get({ id: uuid })
       goodMagnet = video.files[0].magnetUri
 
-      const parsed = magnetUriDecode(goodMagnet)
+      const parsed = await magnetUriDecode(goodMagnet)
       parsed.infoHash = '010597bb88b1968a5693a4fa8267c592ca65f2e9'
 
-      badMagnet = magnetUriEncode(parsed)
+      badMagnet = await magnetUriEncode(parsed)
     }
   })
 
diff --git a/packages/tests/src/api/users/user-import.ts b/packages/tests/src/api/users/user-import.ts
index 798d04220..f67bb0178 100644
--- a/packages/tests/src/api/users/user-import.ts
+++ b/packages/tests/src/api/users/user-import.ts
@@ -401,10 +401,14 @@ function runTest (withObjectStorage: boolean) {
             files: [
               {
                 resolution: 720,
+                height: 720,
+                width: 1280,
                 size: 61000
               },
               {
                 resolution: 240,
+                height: 240,
+                width: 426,
                 size: 23000
               }
             ],
diff --git a/packages/tests/src/api/videos/multiple-servers.ts b/packages/tests/src/api/videos/multiple-servers.ts
index 6c62a1d95..69d13d48e 100644
--- a/packages/tests/src/api/videos/multiple-servers.ts
+++ b/packages/tests/src/api/videos/multiple-servers.ts
@@ -118,6 +118,8 @@ describe('Test multiple servers', function () {
           files: [
             {
               resolution: 720,
+              height: 720,
+              width: 1280,
               size: 572456
             }
           ]
@@ -205,18 +207,26 @@ describe('Test multiple servers', function () {
           files: [
             {
               resolution: 240,
+              height: 240,
+              width: 426,
               size: 270000
             },
             {
               resolution: 360,
+              height: 360,
+              width: 640,
               size: 359000
             },
             {
               resolution: 480,
+              height: 480,
+              width: 854,
               size: 465000
             },
             {
               resolution: 720,
+              height: 720,
+              width: 1280,
               size: 750000
             }
           ],
@@ -312,6 +322,8 @@ describe('Test multiple servers', function () {
           files: [
             {
               resolution: 720,
+              height: 720,
+              width: 1280,
               size: 292677
             }
           ]
@@ -344,6 +356,8 @@ describe('Test multiple servers', function () {
           files: [
             {
               resolution: 720,
+              height: 720,
+              width: 1280,
               size: 218910
             }
           ]
@@ -654,6 +668,8 @@ describe('Test multiple servers', function () {
           files: [
             {
               resolution: 720,
+              height: 720,
+              width: 1280,
               size: 292677
             }
           ],
@@ -1061,18 +1077,26 @@ describe('Test multiple servers', function () {
           files: [
             {
               resolution: 720,
+              height: 720,
+              width: 1280,
               size: 61000
             },
             {
               resolution: 480,
+              height: 480,
+              width: 854,
               size: 40000
             },
             {
               resolution: 360,
+              height: 360,
+              width: 640,
               size: 32000
             },
             {
               resolution: 240,
+              height: 240,
+              width: 426,
               size: 23000
             }
           ]
diff --git a/packages/tests/src/api/videos/single-server.ts b/packages/tests/src/api/videos/single-server.ts
index a60928ebb..82b5fe6ce 100644
--- a/packages/tests/src/api/videos/single-server.ts
+++ b/packages/tests/src/api/videos/single-server.ts
@@ -50,6 +50,8 @@ describe('Test a single server', function () {
       files: [
         {
           resolution: 720,
+          height: 720,
+          width: 1280,
           size: 218910
         }
       ]
@@ -81,6 +83,8 @@ describe('Test a single server', function () {
       files: [
         {
           resolution: 720,
+          height: 720,
+          width: 1280,
           size: 292677
         }
       ]
diff --git a/packages/tests/src/api/videos/video-files.ts b/packages/tests/src/api/videos/video-files.ts
index 1d7c218a4..8d577e876 100644
--- a/packages/tests/src/api/videos/video-files.ts
+++ b/packages/tests/src/api/videos/video-files.ts
@@ -105,7 +105,8 @@ describe('Test videos files', function () {
       const video = await servers[0].videos.get({ id: webVideoId })
       const files = video.files
 
-      await servers[0].videos.removeWebVideoFile({ videoId: webVideoId, fileId: files[0].id })
+      const toDelete = files[0]
+      await servers[0].videos.removeWebVideoFile({ videoId: webVideoId, fileId: toDelete.id })
 
       await waitJobs(servers)
 
@@ -113,7 +114,7 @@ describe('Test videos files', function () {
         const video = await server.videos.get({ id: webVideoId })
 
         expect(video.files).to.have.lengthOf(files.length - 1)
-        expect(video.files.find(f => f.id === files[0].id)).to.not.exist
+        expect(video.files.find(f => f.resolution.id === toDelete.resolution.id)).to.not.exist
       }
     })
 
@@ -151,7 +152,7 @@ describe('Test videos files', function () {
         const video = await server.videos.get({ id: hlsId })
 
         expect(video.streamingPlaylists[0].files).to.have.lengthOf(files.length - 1)
-        expect(video.streamingPlaylists[0].files.find(f => f.id === toDelete.id)).to.not.exist
+        expect(video.streamingPlaylists[0].files.find(f => f.resolution.id === toDelete.resolution.id)).to.not.exist
 
         const { text } = await makeRawRequest({ url: video.streamingPlaylists[0].playlistUrl, expectedStatus: HttpStatusCode.OK_200 })
 
diff --git a/packages/tests/src/api/videos/video-static-file-privacy.ts b/packages/tests/src/api/videos/video-static-file-privacy.ts
index 7c8d14815..8794aef3d 100644
--- a/packages/tests/src/api/videos/video-static-file-privacy.ts
+++ b/packages/tests/src/api/videos/video-static-file-privacy.ts
@@ -1,7 +1,6 @@
 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
 
 import { expect } from 'chai'
-import { decode } from 'magnet-uri'
 import { getAllFiles, wait } from '@peertube/peertube-core-utils'
 import { HttpStatusCode, HttpStatusCodeType, LiveVideo, VideoDetails, VideoPrivacy } from '@peertube/peertube-models'
 import {
@@ -18,7 +17,7 @@ import {
 } from '@peertube/peertube-server-commands'
 import { expectStartWith } from '@tests/shared/checks.js'
 import { checkVideoFileTokenReinjection } from '@tests/shared/streaming-playlists.js'
-import { parseTorrentVideo } from '@tests/shared/webtorrent.js'
+import { magnetUriDecode, parseTorrentVideo } from '@tests/shared/webtorrent.js'
 
 describe('Test video static file privacy', function () {
   let server: PeerTubeServer
@@ -48,7 +47,7 @@ describe('Test video static file privacy', function () {
           const torrent = await parseTorrentVideo(server, file)
           expect(torrent.urlList).to.have.lengthOf(0)
 
-          const magnet = decode(file.magnetUri)
+          const magnet = await magnetUriDecode(file.magnetUri)
           expect(magnet.urlList).to.have.lengthOf(0)
 
           await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
@@ -74,7 +73,7 @@ describe('Test video static file privacy', function () {
           const torrent = await parseTorrentVideo(server, file)
           expect(torrent.urlList[0]).to.not.include('private')
 
-          const magnet = decode(file.magnetUri)
+          const magnet = await magnetUriDecode(file.magnetUri)
           expect(magnet.urlList[0]).to.not.include('private')
 
           await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 })
diff --git a/packages/tests/src/server-helpers/core-utils.ts b/packages/tests/src/server-helpers/core-utils.ts
index f1e7c72f7..c3bec176d 100644
--- a/packages/tests/src/server-helpers/core-utils.ts
+++ b/packages/tests/src/server-helpers/core-utils.ts
@@ -3,7 +3,13 @@
 import { expect } from 'chai'
 import snakeCase from 'lodash-es/snakeCase.js'
 import validator from 'validator'
-import { getAverageTheoreticalBitrate, getMaxTheoreticalBitrate, parseChapters, timeToInt } from '@peertube/peertube-core-utils'
+import {
+  buildAspectRatio,
+  getAverageTheoreticalBitrate,
+  getMaxTheoreticalBitrate,
+  parseChapters,
+  timeToInt
+} from '@peertube/peertube-core-utils'
 import { VideoResolution } from '@peertube/peertube-models'
 import { objectConverter, parseBytes, parseDurationToMs, parseSemVersion } from '@peertube/peertube-server/core/helpers/core-utils.js'
 
@@ -169,6 +175,18 @@ describe('Bitrate', function () {
       expect(getAverageTheoreticalBitrate(test)).to.be.above(test.min * 1000).and.below(test.max * 1000)
     }
   })
+
+  describe('Ratio', function () {
+
+    it('Should have the correct aspect ratio in landscape', function () {
+      expect(buildAspectRatio({ width: 1920, height: 1080 })).to.equal(1.7778)
+      expect(buildAspectRatio({ width: 1000, height: 1000 })).to.equal(1)
+    })
+
+    it('Should have the correct aspect ratio in portrait', function () {
+      expect(buildAspectRatio({ width: 1080, height: 1920 })).to.equal(0.5625)
+    })
+  })
 })
 
 describe('Parse semantic version string', function () {
diff --git a/packages/tests/src/shared/checks.ts b/packages/tests/src/shared/checks.ts
index 0f1d9d02e..365d02e25 100644
--- a/packages/tests/src/shared/checks.ts
+++ b/packages/tests/src/shared/checks.ts
@@ -103,9 +103,15 @@ async function testImage (url: string, imageName: string, imageHTTPPath: string,
     ? PNG.sync.read(data)
     : JPEG.decode(data)
 
-  const result = pixelmatch(img1.data, img2.data, null, img1.width, img1.height, { threshold: 0.1 })
+  const errorMsg = `${imageHTTPPath} image is not the same as ${imageName}${extension}`
 
-  expect(result).to.equal(0, `${imageHTTPPath} image is not the same as ${imageName}${extension}`)
+  try {
+    const result = pixelmatch(img1.data, img2.data, null, img1.width, img1.height, { threshold: 0.1 })
+
+    expect(result).to.equal(0, errorMsg)
+  } catch (err) {
+    throw new Error(`${errorMsg}: ${err.message}`)
+  }
 }
 
 async function testFileExistsOrNot (server: PeerTubeServer, directory: string, filePath: string, exist: boolean) {
diff --git a/packages/tests/src/shared/live.ts b/packages/tests/src/shared/live.ts
index 9c7991b0d..2c7f02be0 100644
--- a/packages/tests/src/shared/live.ts
+++ b/packages/tests/src/shared/live.ts
@@ -66,6 +66,8 @@ async function testLiveVideoResolutions (options: {
     expect(data.find(v => v.uuid === liveVideoId)).to.exist
 
     const video = await server.videos.get({ id: liveVideoId })
+
+    expect(video.aspectRatio).to.equal(1.7778)
     expect(video.streamingPlaylists).to.have.lengthOf(1)
 
     const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS)
diff --git a/packages/tests/src/shared/streaming-playlists.ts b/packages/tests/src/shared/streaming-playlists.ts
index ec5a0187a..8a601266f 100644
--- a/packages/tests/src/shared/streaming-playlists.ts
+++ b/packages/tests/src/shared/streaming-playlists.ts
@@ -145,6 +145,9 @@ async function completeCheckHlsPlaylist (options: {
         expect(file.resolution.label).to.equal(resolution + 'p')
       }
 
+      expect(Math.min(file.height, file.width)).to.equal(resolution)
+      expect(Math.max(file.height, file.width)).to.be.greaterThan(resolution)
+
       expect(file.magnetUri).to.have.lengthOf.above(2)
       await checkWebTorrentWorks(file.magnetUri)
 
diff --git a/packages/tests/src/shared/videos.ts b/packages/tests/src/shared/videos.ts
index 0bf1956af..ede4ecc6c 100644
--- a/packages/tests/src/shared/videos.ts
+++ b/packages/tests/src/shared/videos.ts
@@ -26,6 +26,8 @@ export async function completeWebVideoFilesCheck (options: {
   fixture: string
   files: {
     resolution: number
+    width?: number
+    height?: number
     size?: number
   }[]
   objectStorageBaseUrl?: string
@@ -84,7 +86,9 @@ export async function completeWebVideoFilesCheck (options: {
         makeRawRequest({
           url: file.fileDownloadUrl,
           token,
-          expectedStatus: objectStorageBaseUrl ? HttpStatusCode.FOUND_302 : HttpStatusCode.OK_200
+          expectedStatus: objectStorageBaseUrl
+            ? HttpStatusCode.FOUND_302
+            : HttpStatusCode.OK_200
         })
       ])
     }
@@ -97,6 +101,12 @@ export async function completeWebVideoFilesCheck (options: {
       expect(file.resolution.label).to.equal(attributeFile.resolution + 'p')
     }
 
+    if (attributeFile.width !== undefined) expect(file.width).to.equal(attributeFile.width)
+    if (attributeFile.height !== undefined) expect(file.height).to.equal(attributeFile.height)
+
+    expect(Math.min(file.height, file.width)).to.equal(file.resolution.id)
+    expect(Math.max(file.height, file.width)).to.be.greaterThan(file.resolution.id)
+
     if (attributeFile.size) {
       const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
       const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
@@ -156,6 +166,8 @@ export async function completeVideoCheck (options: {
     files?: {
       resolution: number
       size: number
+      width: number
+      height: number
     }[]
 
     hls?: {
diff --git a/packages/tests/src/shared/webtorrent.ts b/packages/tests/src/shared/webtorrent.ts
index 8f83ddf17..a50ab464a 100644
--- a/packages/tests/src/shared/webtorrent.ts
+++ b/packages/tests/src/shared/webtorrent.ts
@@ -4,6 +4,7 @@ import { basename, join } from 'path'
 import type { Instance, Torrent } from 'webtorrent'
 import { VideoFile } from '@peertube/peertube-models'
 import { PeerTubeServer } from '@peertube/peertube-server-commands'
+import type { Instance as MagnetUriInstance } from 'magnet-uri'
 
 let webtorrent: Instance
 
@@ -28,6 +29,14 @@ export async function parseTorrentVideo (server: PeerTubeServer, file: VideoFile
   return (await import('parse-torrent')).default(data)
 }
 
+export async function magnetUriDecode (data: string) {
+  return (await import('magnet-uri')).decode(data)
+}
+
+export async function magnetUriEncode (data: MagnetUriInstance) {
+  return (await import('magnet-uri')).encode(data)
+}
+
 // ---------------------------------------------------------------------------
 // Private
 // ---------------------------------------------------------------------------
diff --git a/server/core/controllers/api/videos/source.ts b/server/core/controllers/api/videos/source.ts
index d5882d489..fd2631110 100644
--- a/server/core/controllers/api/videos/source.ts
+++ b/server/core/controllers/api/videos/source.ts
@@ -23,6 +23,7 @@ import {
   replaceVideoSourceResumableValidator,
   videoSourceGetLatestValidator
 } from '../../../middlewares/index.js'
+import { buildAspectRatio } from '@peertube/peertube-core-utils'
 
 const lTags = loggerTagsFactory('api', 'video')
 
@@ -96,6 +97,7 @@ async function replaceVideoSourceResumable (req: express.Request, res: express.R
       video.state = buildNextVideoState()
       video.duration = videoPhysicalFile.duration
       video.inputFileUpdatedAt = inputFileUpdatedAt
+      video.aspectRatio = buildAspectRatio({ width: videoFile.width, height: videoFile.height })
       await video.save({ transaction })
 
       await autoBlacklistVideoIfNeeded({
diff --git a/server/core/helpers/activity-pub-utils.ts b/server/core/helpers/activity-pub-utils.ts
index aa05e6031..7ea701d34 100644
--- a/server/core/helpers/activity-pub-utils.ts
+++ b/server/core/helpers/activity-pub-utils.ts
@@ -94,6 +94,10 @@ const contextStore: { [ id in ContextType ]: (string | { [ id: string ]: string
       '@type': 'sc:Number',
       '@id': 'pt:tileDuration'
     },
+    aspectRatio: {
+      '@type': 'sc:Float',
+      '@id': 'pt:aspectRatio'
+    },
 
     originallyPublishedAt: 'sc:datePublished',
 
diff --git a/server/core/initializers/constants.ts b/server/core/initializers/constants.ts
index 0fb0710aa..5cc8a53e2 100644
--- a/server/core/initializers/constants.ts
+++ b/server/core/initializers/constants.ts
@@ -45,7 +45,7 @@ import { cpus } from 'os'
 
 // ---------------------------------------------------------------------------
 
-const LAST_MIGRATION_VERSION = 820
+const LAST_MIGRATION_VERSION = 825
 
 // ---------------------------------------------------------------------------
 
diff --git a/server/core/initializers/migrations/0825-video-ratio.ts b/server/core/initializers/migrations/0825-video-ratio.ts
new file mode 100644
index 000000000..4bfd4c402
--- /dev/null
+++ b/server/core/initializers/migrations/0825-video-ratio.ts
@@ -0,0 +1,43 @@
+import * as Sequelize from 'sequelize'
+
+async function up (utils: {
+  transaction: Sequelize.Transaction
+  queryInterface: Sequelize.QueryInterface
+  sequelize: Sequelize.Sequelize
+}): Promise<void> {
+  {
+    const data = {
+      type: Sequelize.INTEGER,
+      defaultValue: null,
+      allowNull: true
+    }
+    await utils.queryInterface.addColumn('videoFile', 'width', data)
+  }
+
+  {
+    const data = {
+      type: Sequelize.INTEGER,
+      defaultValue: null,
+      allowNull: true
+    }
+    await utils.queryInterface.addColumn('videoFile', 'height', data)
+  }
+
+  {
+    const data = {
+      type: Sequelize.FLOAT,
+      defaultValue: null,
+      allowNull: true
+    }
+    await utils.queryInterface.addColumn('video', 'aspectRatio', data)
+  }
+}
+
+function down (options) {
+  throw new Error('Not implemented.')
+}
+
+export {
+  up,
+  down
+}
diff --git a/server/core/lib/activitypub/videos/shared/object-to-model-attributes.ts b/server/core/lib/activitypub/videos/shared/object-to-model-attributes.ts
index 9657bd172..71846172e 100644
--- a/server/core/lib/activitypub/videos/shared/object-to-model-attributes.ts
+++ b/server/core/lib/activitypub/videos/shared/object-to-model-attributes.ts
@@ -55,7 +55,6 @@ function getFileAttributesFromUrl (
   urls: (ActivityTagObject | ActivityUrlObject)[]
 ) {
   const fileUrls = urls.filter(u => isAPVideoUrlObject(u)) as ActivityVideoUrlObject[]
-
   if (fileUrls.length === 0) return []
 
   const attributes: FilteredModelAttributes<VideoFileModel>[] = []
@@ -96,6 +95,9 @@ function getFileAttributesFromUrl (
       fps: fileUrl.fps || -1,
       metadataUrl: metadata?.href,
 
+      width: fileUrl.width,
+      height: fileUrl.height,
+
       // Use the name of the remote file because we don't proxify video file requests
       filename: basename(fileUrl.href),
       fileUrl: fileUrl.href,
@@ -223,6 +225,7 @@ function getVideoAttributesFromObject (videoChannel: MChannelId, videoObject: Vi
     waitTranscoding: videoObject.waitTranscoding,
     isLive: videoObject.isLiveBroadcast,
     state: videoObject.state,
+    aspectRatio: videoObject.aspectRatio,
     channelId: videoChannel.id,
     duration: getDurationFromActivityStream(videoObject.duration),
     createdAt: new Date(videoObject.published),
diff --git a/server/core/lib/activitypub/videos/updater.ts b/server/core/lib/activitypub/videos/updater.ts
index a8d1558fb..e722744bd 100644
--- a/server/core/lib/activitypub/videos/updater.ts
+++ b/server/core/lib/activitypub/videos/updater.ts
@@ -143,6 +143,7 @@ export class APVideoUpdater extends APVideoAbstractBuilder {
     this.video.channelId = videoData.channelId
     this.video.views = videoData.views
     this.video.isLive = videoData.isLive
+    this.video.aspectRatio = videoData.aspectRatio
 
     // Ensures we update the updatedAt attribute, even if main attributes did not change
     this.video.changed('updatedAt', true)
diff --git a/server/core/lib/job-queue/handlers/generate-storyboard.ts b/server/core/lib/job-queue/handlers/generate-storyboard.ts
index 62ae64189..b4539aabb 100644
--- a/server/core/lib/job-queue/handlers/generate-storyboard.ts
+++ b/server/core/lib/job-queue/handlers/generate-storyboard.ts
@@ -51,10 +51,10 @@ async function processGenerateStoryboard (job: Job): Promise<void> {
 
       if (videoStreamInfo.isPortraitMode) {
         spriteHeight = STORYBOARD.SPRITE_MAX_SIZE
-        spriteWidth = Math.round(STORYBOARD.SPRITE_MAX_SIZE / videoStreamInfo.ratio)
+        spriteWidth = Math.round(spriteHeight * videoStreamInfo.ratio)
       } else {
-        spriteHeight = Math.round(STORYBOARD.SPRITE_MAX_SIZE / videoStreamInfo.ratio)
         spriteWidth = STORYBOARD.SPRITE_MAX_SIZE
+        spriteHeight = Math.round(spriteWidth / videoStreamInfo.ratio)
       }
 
       const ffmpeg = new FFmpegImage(getFFmpegCommandWrapperOptions('thumbnail'))
diff --git a/server/core/lib/job-queue/handlers/video-file-import.ts b/server/core/lib/job-queue/handlers/video-file-import.ts
index a306c6b80..ae876b355 100644
--- a/server/core/lib/job-queue/handlers/video-file-import.ts
+++ b/server/core/lib/job-queue/handlers/video-file-import.ts
@@ -1,20 +1,17 @@
 import { Job } from 'bullmq'
 import { copy } from 'fs-extra/esm'
-import { stat } from 'fs/promises'
-import { VideoFileImportPayload, FileStorage } from '@peertube/peertube-models'
+import { VideoFileImportPayload } from '@peertube/peertube-models'
 import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent.js'
 import { CONFIG } from '@server/initializers/config.js'
 import { federateVideoIfNeeded } from '@server/lib/activitypub/videos/index.js'
-import { generateWebVideoFilename } from '@server/lib/paths.js'
 import { VideoPathManager } from '@server/lib/video-path-manager.js'
-import { VideoFileModel } from '@server/models/video/video-file.js'
 import { VideoModel } from '@server/models/video/video.js'
 import { MVideoFullLight } from '@server/types/models/index.js'
-import { getLowercaseExtension } from '@peertube/peertube-node-utils'
-import { getVideoStreamDimensionsInfo, getVideoStreamFPS } from '@peertube/peertube-ffmpeg'
+import { getVideoStreamDimensionsInfo } from '@peertube/peertube-ffmpeg'
 import { logger } from '../../../helpers/logger.js'
 import { JobQueue } from '../job-queue.js'
 import { buildMoveJob } from '@server/lib/video-jobs.js'
+import { buildNewFile } from '@server/lib/video-file.js'
 
 async function processVideoFileImport (job: Job) {
   const payload = job.data as VideoFileImportPayload
@@ -48,11 +45,6 @@ export {
 
 async function updateVideoFile (video: MVideoFullLight, inputFilePath: string) {
   const { resolution } = await getVideoStreamDimensionsInfo(inputFilePath)
-  const { size } = await stat(inputFilePath)
-  const fps = await getVideoStreamFPS(inputFilePath)
-
-  const fileExt = getLowercaseExtension(inputFilePath)
-
   const currentVideoFile = video.VideoFiles.find(videoFile => videoFile.resolution === resolution)
 
   if (currentVideoFile) {
@@ -64,15 +56,8 @@ async function updateVideoFile (video: MVideoFullLight, inputFilePath: string) {
     await currentVideoFile.destroy()
   }
 
-  const newVideoFile = new VideoFileModel({
-    resolution,
-    extname: fileExt,
-    filename: generateWebVideoFilename(resolution, fileExt),
-    storage: FileStorage.FILE_SYSTEM,
-    size,
-    fps,
-    videoId: video.id
-  })
+  const newVideoFile = await buildNewFile({ mode: 'web-video', path: inputFilePath })
+  newVideoFile.videoId = video.id
 
   const outputPath = VideoPathManager.Instance.getFSVideoFileOutputPath(video, newVideoFile)
   await copy(inputFilePath, outputPath)
diff --git a/server/core/lib/job-queue/handlers/video-import.ts b/server/core/lib/job-queue/handlers/video-import.ts
index 6ebe973db..db8f84077 100644
--- a/server/core/lib/job-queue/handlers/video-import.ts
+++ b/server/core/lib/job-queue/handlers/video-import.ts
@@ -10,15 +10,12 @@ import {
   VideoImportTorrentPayload,
   VideoImportTorrentPayloadType,
   VideoImportYoutubeDLPayload,
-  VideoImportYoutubeDLPayloadType,
-  VideoResolution,
-  VideoState
+  VideoImportYoutubeDLPayloadType, VideoState
 } from '@peertube/peertube-models'
 import { retryTransactionWrapper } from '@server/helpers/database-utils.js'
 import { YoutubeDLWrapper } from '@server/helpers/youtube-dl/index.js'
 import { CONFIG } from '@server/initializers/config.js'
 import { isPostImportVideoAccepted } from '@server/lib/moderation.js'
-import { generateWebVideoFilename } from '@server/lib/paths.js'
 import { Hooks } from '@server/lib/plugins/hooks.js'
 import { ServerConfigManager } from '@server/lib/server-config-manager.js'
 import { createOptimizeOrMergeAudioJobs } from '@server/lib/transcoding/create-transcoding-job.js'
@@ -28,14 +25,9 @@ import { buildNextVideoState } from '@server/lib/video-state.js'
 import { buildMoveJob, buildStoryboardJobIfNeeded } from '@server/lib/video-jobs.js'
 import { MUserId, MVideoFile, MVideoFullLight } from '@server/types/models/index.js'
 import { MVideoImport, MVideoImportDefault, MVideoImportDefaultFiles, MVideoImportVideo } from '@server/types/models/video/video-import.js'
-import { getLowercaseExtension } from '@peertube/peertube-node-utils'
 import {
   ffprobePromise,
-  getChaptersFromContainer,
-  getVideoStreamDimensionsInfo,
-  getVideoStreamDuration,
-  getVideoStreamFPS,
-  isAudioFile
+  getChaptersFromContainer, getVideoStreamDuration
 } from '@peertube/peertube-ffmpeg'
 import { logger } from '../../../helpers/logger.js'
 import { getSecureTorrentName } from '../../../helpers/utils.js'
@@ -51,6 +43,8 @@ import { generateLocalVideoMiniature } from '../../thumbnail.js'
 import { JobQueue } from '../job-queue.js'
 import { replaceChaptersIfNotExist } from '@server/lib/video-chapters.js'
 import { FfprobeData } from 'fluent-ffmpeg'
+import { buildNewFile } from '@server/lib/video-file.js'
+import { buildAspectRatio } from '@peertube/peertube-core-utils'
 
 async function processVideoImport (job: Job): Promise<VideoImportPreventExceptionResult> {
   const payload = job.data as VideoImportPayload
@@ -129,46 +123,31 @@ type ProcessFileOptions = {
   videoImportId: number
 }
 async function processFile (downloader: () => Promise<string>, videoImport: MVideoImportDefault, options: ProcessFileOptions) {
-  let tempVideoPath: string
+  let tmpVideoPath: string
   let videoFile: VideoFileModel
 
   try {
     // Download video from youtubeDL
-    tempVideoPath = await downloader()
+    tmpVideoPath = await downloader()
 
     // Get information about this video
-    const stats = await stat(tempVideoPath)
+    const stats = await stat(tmpVideoPath)
     const isAble = await isUserQuotaValid({ userId: videoImport.User.id, uploadSize: stats.size })
     if (isAble === false) {
       throw new Error('The user video quota is exceeded with this video to import.')
     }
 
-    const ffprobe = await ffprobePromise(tempVideoPath)
-
-    const { resolution } = await isAudioFile(tempVideoPath, ffprobe)
-      ? { resolution: VideoResolution.H_NOVIDEO }
-      : await getVideoStreamDimensionsInfo(tempVideoPath, ffprobe)
-
-    const fps = await getVideoStreamFPS(tempVideoPath, ffprobe)
-    const duration = await getVideoStreamDuration(tempVideoPath, ffprobe)
+    const ffprobe = await ffprobePromise(tmpVideoPath)
+    const duration = await getVideoStreamDuration(tmpVideoPath, ffprobe)
 
     const containerChapters = await getChaptersFromContainer({
-      path: tempVideoPath,
+      path: tmpVideoPath,
       maxTitleLength: CONSTRAINTS_FIELDS.VIDEO_CHAPTERS.TITLE.max,
       ffprobe
     })
 
-    // Prepare video file object for creation in database
-    const fileExt = getLowercaseExtension(tempVideoPath)
-    const videoFileData = {
-      extname: fileExt,
-      resolution,
-      size: stats.size,
-      filename: generateWebVideoFilename(resolution, fileExt),
-      fps,
-      videoId: videoImport.videoId
-    }
-    videoFile = new VideoFileModel(videoFileData)
+    videoFile = await buildNewFile({ mode: 'web-video', ffprobe, path: tmpVideoPath })
+    videoFile.videoId = videoImport.videoId
 
     const hookName = options.type === 'youtube-dl'
       ? 'filter:api.video.post-import-url.accept.result'
@@ -178,7 +157,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid
     const acceptParameters = {
       videoImport,
       video: videoImport.Video,
-      videoFilePath: tempVideoPath,
+      videoFilePath: tmpVideoPath,
       videoFile,
       user: videoImport.User
     }
@@ -201,9 +180,9 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid
 
       // Move file
       const videoDestFile = VideoPathManager.Instance.getFSVideoFileOutputPath(videoImportWithFiles.Video, videoFile)
-      await move(tempVideoPath, videoDestFile)
+      await move(tmpVideoPath, videoDestFile)
 
-      tempVideoPath = null // This path is not used anymore
+      tmpVideoPath = null // This path is not used anymore
 
       const thumbnails = await generateMiniature({ videoImportWithFiles, videoFile, ffprobe })
 
@@ -221,6 +200,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid
           // Update video DB object
           video.duration = duration
           video.state = buildNextVideoState(video.state)
+          video.aspectRatio = buildAspectRatio({ width: videoFile.width, height: videoFile.height })
           await video.save({ transaction: t })
 
           for (const thumbnail of thumbnails) {
@@ -248,7 +228,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid
       videoFileLockReleaser()
     }
   } catch (err) {
-    await onImportError(err, tempVideoPath, videoImport)
+    await onImportError(err, tmpVideoPath, videoImport)
 
     throw err
   }
diff --git a/server/core/lib/job-queue/handlers/video-live-ending.ts b/server/core/lib/job-queue/handlers/video-live-ending.ts
index 206ce2108..1a326645d 100644
--- a/server/core/lib/job-queue/handlers/video-live-ending.ts
+++ b/server/core/lib/job-queue/handlers/video-live-ending.ts
@@ -125,6 +125,7 @@ async function saveReplayToExternalVideo (options: {
     waitTranscoding: true,
     nsfw: liveVideo.nsfw,
     description: liveVideo.description,
+    aspectRatio: liveVideo.aspectRatio,
     support: liveVideo.support,
     privacy: replaySettings.privacy,
     channelId: liveVideo.channelId
diff --git a/server/core/lib/live/live-manager.ts b/server/core/lib/live/live-manager.ts
index 3ef1661b8..797b3bdfa 100644
--- a/server/core/lib/live/live-manager.ts
+++ b/server/core/lib/live/live-manager.ts
@@ -328,7 +328,7 @@ class LiveManager {
     allResolutions: number[]
     hasAudio: boolean
   }) {
-    const { sessionId, videoLive, user } = options
+    const { sessionId, videoLive, user, ratio } = options
     const videoUUID = videoLive.Video.uuid
     const localLTags = lTags(sessionId, videoUUID)
 
@@ -345,7 +345,7 @@ class LiveManager {
       ...pick(options, [ 'inputLocalUrl', 'inputPublicUrl', 'bitrate', 'ratio', 'fps', 'allResolutions', 'hasAudio' ])
     })
 
-    muxingSession.on('live-ready', () => this.publishAndFederateLive(videoLive, localLTags))
+    muxingSession.on('live-ready', () => this.publishAndFederateLive({ live: videoLive, ratio, localLTags }))
 
     muxingSession.on('bad-socket-health', ({ videoUUID }) => {
       logger.error(
@@ -405,7 +405,13 @@ class LiveManager {
       })
   }
 
-  private async publishAndFederateLive (live: MVideoLiveVideo, localLTags: { tags: (string | number)[] }) {
+  private async publishAndFederateLive (options: {
+    live: MVideoLiveVideo
+    ratio: number
+    localLTags: { tags: (string | number)[] }
+  }) {
+    const { live, ratio, localLTags } = options
+
     const videoId = live.videoId
 
     try {
@@ -415,6 +421,7 @@ class LiveManager {
 
       video.state = VideoState.PUBLISHED
       video.publishedAt = new Date()
+      video.aspectRatio = ratio
       await video.save()
 
       live.Video = video
diff --git a/server/core/lib/local-video-creator.ts b/server/core/lib/local-video-creator.ts
index a41937ecc..b2e8acc99 100644
--- a/server/core/lib/local-video-creator.ts
+++ b/server/core/lib/local-video-creator.ts
@@ -33,6 +33,7 @@ import { replaceChapters, replaceChaptersFromDescriptionIfNeeded } from './video
 import { LoggerTagsFn, logger } from '@server/helpers/logger.js'
 import { retryTransactionWrapper } from '@server/helpers/database-utils.js'
 import { federateVideoIfNeeded } from './activitypub/videos/federate.js'
+import { buildAspectRatio } from '@peertube/peertube-core-utils'
 
 type VideoAttributes = Omit<VideoCreate, 'channelId'> & {
   duration: number
@@ -116,6 +117,8 @@ export class LocalVideoCreator {
 
       const destination = VideoPathManager.Instance.getFSVideoFileOutputPath(this.video, this.videoFile)
       await move(this.videoFilePath, destination)
+
+      this.video.aspectRatio = buildAspectRatio({ width: this.videoFile.width, height: this.videoFile.height })
     }
 
     const thumbnails = await this.createThumbnails()
diff --git a/server/core/lib/runners/job-handlers/shared/vod-helpers.ts b/server/core/lib/runners/job-handlers/shared/vod-helpers.ts
index d0eb6264f..3c63206bc 100644
--- a/server/core/lib/runners/job-handlers/shared/vod-helpers.ts
+++ b/server/core/lib/runners/job-handlers/shared/vod-helpers.ts
@@ -1,50 +1,24 @@
-import { move } from 'fs-extra/esm'
-import { dirname, join } from 'path'
 import { logger, LoggerTagsFn } from '@server/helpers/logger.js'
 import { onTranscodingEnded } from '@server/lib/transcoding/ended-transcoding.js'
 import { onWebVideoFileTranscoding } from '@server/lib/transcoding/web-transcoding.js'
-import { buildNewFile } from '@server/lib/video-file.js'
 import { VideoModel } from '@server/models/video/video.js'
 import { MVideoFullLight } from '@server/types/models/index.js'
 import { MRunnerJob } from '@server/types/models/runners/index.js'
 import { RunnerJobVODAudioMergeTranscodingPrivatePayload, RunnerJobVODWebVideoTranscodingPrivatePayload } from '@peertube/peertube-models'
-import { lTags } from '@server/lib/object-storage/shared/logger.js'
 
 export async function onVODWebVideoOrAudioMergeTranscodingJob (options: {
   video: MVideoFullLight
   videoFilePath: string
   privatePayload: RunnerJobVODWebVideoTranscodingPrivatePayload | RunnerJobVODAudioMergeTranscodingPrivatePayload
+  wasAudioFile: boolean
 }) {
-  const { video, videoFilePath, privatePayload } = options
+  const { video, videoFilePath, privatePayload, wasAudioFile } = options
 
-  const videoFile = await buildNewFile({ path: videoFilePath, mode: 'web-video' })
-  videoFile.videoId = video.id
+  const deleteWebInputVideoFile = privatePayload.deleteInputFileId
+    ? video.VideoFiles.find(f => f.id === privatePayload.deleteInputFileId)
+    : undefined
 
-  const newVideoFilePath = join(dirname(videoFilePath), videoFile.filename)
-  await move(videoFilePath, newVideoFilePath)
-
-  await onWebVideoFileTranscoding({
-    video,
-    videoFile,
-    videoOutputPath: newVideoFilePath
-  })
-
-  if (privatePayload.deleteInputFileId) {
-    const inputFile = video.VideoFiles.find(f => f.id === privatePayload.deleteInputFileId)
-
-    if (inputFile) {
-      await video.removeWebVideoFile(inputFile)
-      await inputFile.destroy()
-
-      video.VideoFiles = video.VideoFiles.filter(f => f.id !== inputFile.id)
-    } else {
-      logger.error(
-        'Cannot delete input file %d of video %s: does not exist anymore',
-        privatePayload.deleteInputFileId, video.uuid,
-        { ...lTags(video.uuid), privatePayload }
-      )
-    }
-  }
+  await onWebVideoFileTranscoding({ video, videoOutputPath: videoFilePath, deleteWebInputVideoFile, wasAudioFile })
 
   await onTranscodingEnded({ isNewVideo: privatePayload.isNewVideo, moveVideoToNextState: true, video })
 }
diff --git a/server/core/lib/runners/job-handlers/vod-audio-merge-transcoding-job-handler.ts b/server/core/lib/runners/job-handlers/vod-audio-merge-transcoding-job-handler.ts
index bcae1b27a..b93ab37a4 100644
--- a/server/core/lib/runners/job-handlers/vod-audio-merge-transcoding-job-handler.ts
+++ b/server/core/lib/runners/job-handlers/vod-audio-merge-transcoding-job-handler.ts
@@ -4,7 +4,6 @@ import { MVideo } from '@server/types/models/index.js'
 import { MRunnerJob } from '@server/types/models/runners/index.js'
 import { pick } from '@peertube/peertube-core-utils'
 import { buildUUID } from '@peertube/peertube-node-utils'
-import { getVideoStreamDuration } from '@peertube/peertube-ffmpeg'
 import {
   RunnerJobUpdatePayload,
   RunnerJobVODAudioMergeTranscodingPayload,
@@ -77,12 +76,7 @@ export class VODAudioMergeTranscodingJobHandler extends AbstractVODTranscodingJo
 
     const videoFilePath = resultPayload.videoFile as string
 
-    // ffmpeg generated a new video file, so update the video duration
-    // See https://trac.ffmpeg.org/ticket/5456
-    video.duration = await getVideoStreamDuration(videoFilePath)
-    await video.save()
-
-    await onVODWebVideoOrAudioMergeTranscodingJob({ video, videoFilePath, privatePayload })
+    await onVODWebVideoOrAudioMergeTranscodingJob({ video, videoFilePath, privatePayload, wasAudioFile: true })
 
     logger.info(
       'Runner VOD audio merge transcoding job %s for %s ended.',
diff --git a/server/core/lib/runners/job-handlers/vod-hls-transcoding-job-handler.ts b/server/core/lib/runners/job-handlers/vod-hls-transcoding-job-handler.ts
index e0b90313f..0cb011d95 100644
--- a/server/core/lib/runners/job-handlers/vod-hls-transcoding-job-handler.ts
+++ b/server/core/lib/runners/job-handlers/vod-hls-transcoding-job-handler.ts
@@ -1,11 +1,7 @@
-import { move } from 'fs-extra/esm'
-import { dirname, join } from 'path'
 import { logger } from '@server/helpers/logger.js'
-import { renameVideoFileInPlaylist } from '@server/lib/hls.js'
-import { getHlsResolutionPlaylistFilename } from '@server/lib/paths.js'
 import { onTranscodingEnded } from '@server/lib/transcoding/ended-transcoding.js'
 import { onHLSVideoFileTranscoding } from '@server/lib/transcoding/hls-transcoding.js'
-import { buildNewFile, removeAllWebVideoFiles } from '@server/lib/video-file.js'
+import { removeAllWebVideoFiles } from '@server/lib/video-file.js'
 import { VideoJobInfoModel } from '@server/models/video/video-job-info.js'
 import { MVideo } from '@server/types/models/index.js'
 import { MRunnerJob } from '@server/types/models/runners/index.js'
@@ -84,21 +80,10 @@ export class VODHLSTranscodingJobHandler extends AbstractVODTranscodingJobHandle
     const videoFilePath = resultPayload.videoFile as string
     const resolutionPlaylistFilePath = resultPayload.resolutionPlaylistFile as string
 
-    const videoFile = await buildNewFile({ path: videoFilePath, mode: 'hls' })
-    const newVideoFilePath = join(dirname(videoFilePath), videoFile.filename)
-    await move(videoFilePath, newVideoFilePath)
-
-    const resolutionPlaylistFilename = getHlsResolutionPlaylistFilename(videoFile.filename)
-    const newResolutionPlaylistFilePath = join(dirname(resolutionPlaylistFilePath), resolutionPlaylistFilename)
-    await move(resolutionPlaylistFilePath, newResolutionPlaylistFilePath)
-
-    await renameVideoFileInPlaylist(newResolutionPlaylistFilePath, videoFile.filename)
-
     await onHLSVideoFileTranscoding({
       video,
-      videoFile,
-      m3u8OutputPath: newResolutionPlaylistFilePath,
-      videoOutputPath: newVideoFilePath
+      m3u8OutputPath: resolutionPlaylistFilePath,
+      videoOutputPath: videoFilePath
     })
 
     await onTranscodingEnded({ isNewVideo: privatePayload.isNewVideo, moveVideoToNextState: true, video })
diff --git a/server/core/lib/runners/job-handlers/vod-web-video-transcoding-job-handler.ts b/server/core/lib/runners/job-handlers/vod-web-video-transcoding-job-handler.ts
index a23adbc3f..12a846985 100644
--- a/server/core/lib/runners/job-handlers/vod-web-video-transcoding-job-handler.ts
+++ b/server/core/lib/runners/job-handlers/vod-web-video-transcoding-job-handler.ts
@@ -75,7 +75,7 @@ export class VODWebVideoTranscodingJobHandler extends AbstractVODTranscodingJobH
 
     const videoFilePath = resultPayload.videoFile as string
 
-    await onVODWebVideoOrAudioMergeTranscodingJob({ video, videoFilePath, privatePayload })
+    await onVODWebVideoOrAudioMergeTranscodingJob({ video, videoFilePath, privatePayload, wasAudioFile: false })
 
     logger.info(
       'Runner VOD web video transcoding job %s for %s ended.',
diff --git a/server/core/lib/transcoding/hls-transcoding.ts b/server/core/lib/transcoding/hls-transcoding.ts
index 15182f5e6..fcb358330 100644
--- a/server/core/lib/transcoding/hls-transcoding.ts
+++ b/server/core/lib/transcoding/hls-transcoding.ts
@@ -1,20 +1,19 @@
 import { MutexInterface } from 'async-mutex'
 import { Job } from 'bullmq'
 import { ensureDir, move } from 'fs-extra/esm'
-import { stat } from 'fs/promises'
-import { basename, extname as extnameUtil, join } from 'path'
+import { join } from 'path'
 import { pick } from '@peertube/peertube-core-utils'
 import { retryTransactionWrapper } from '@server/helpers/database-utils.js'
 import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent.js'
 import { sequelizeTypescript } from '@server/initializers/database.js'
-import { MVideo, MVideoFile } from '@server/types/models/index.js'
-import { getVideoStreamDuration, getVideoStreamFPS } from '@peertube/peertube-ffmpeg'
+import { MVideo } from '@server/types/models/index.js'
+import { getVideoStreamDuration } from '@peertube/peertube-ffmpeg'
 import { CONFIG } from '../../initializers/config.js'
 import { VideoFileModel } from '../../models/video/video-file.js'
 import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist.js'
-import { updatePlaylistAfterFileChange } from '../hls.js'
+import { renameVideoFileInPlaylist, updatePlaylistAfterFileChange } from '../hls.js'
 import { generateHLSVideoFilename, getHlsResolutionPlaylistFilename } from '../paths.js'
-import { buildFileMetadata } from '../video-file.js'
+import { buildNewFile } from '../video-file.js'
 import { VideoPathManager } from '../video-path-manager.js'
 import { buildFFmpegVOD } from './shared/index.js'
 
@@ -55,12 +54,11 @@ export function generateHlsPlaylistResolution (options: {
 
 export async function onHLSVideoFileTranscoding (options: {
   video: MVideo
-  videoFile: MVideoFile
   videoOutputPath: string
   m3u8OutputPath: string
   filesLockedInParent?: boolean // default false
 }) {
-  const { video, videoFile, videoOutputPath, m3u8OutputPath, filesLockedInParent = false } = options
+  const { video, videoOutputPath, m3u8OutputPath, filesLockedInParent = false } = options
 
   // Create or update the playlist
   const playlist = await retryTransactionWrapper(() => {
@@ -68,7 +66,9 @@ export async function onHLSVideoFileTranscoding (options: {
       return VideoStreamingPlaylistModel.loadOrGenerate(video, transaction)
     })
   })
-  videoFile.videoStreamingPlaylistId = playlist.id
+
+  const newVideoFile = await buildNewFile({ mode: 'hls', path: videoOutputPath })
+  newVideoFile.videoStreamingPlaylistId = playlist.id
 
   const mutexReleaser = !filesLockedInParent
     ? await VideoPathManager.Instance.lockFiles(video.uuid)
@@ -77,33 +77,33 @@ export async function onHLSVideoFileTranscoding (options: {
   try {
     await video.reload()
 
-    const videoFilePath = VideoPathManager.Instance.getFSVideoFileOutputPath(playlist, videoFile)
+    const videoFilePath = VideoPathManager.Instance.getFSVideoFileOutputPath(playlist, newVideoFile)
     await ensureDir(VideoPathManager.Instance.getFSHLSOutputPath(video))
 
     // Move playlist file
-    const resolutionPlaylistPath = VideoPathManager.Instance.getFSHLSOutputPath(video, basename(m3u8OutputPath))
+    const resolutionPlaylistPath = VideoPathManager.Instance.getFSHLSOutputPath(
+      video,
+      getHlsResolutionPlaylistFilename(newVideoFile.filename)
+    )
     await move(m3u8OutputPath, resolutionPlaylistPath, { overwrite: true })
+
     // Move video file
     await move(videoOutputPath, videoFilePath, { overwrite: true })
 
+    await renameVideoFileInPlaylist(resolutionPlaylistPath, newVideoFile.filename)
+
     // Update video duration if it was not set (in case of a live for example)
     if (!video.duration) {
       video.duration = await getVideoStreamDuration(videoFilePath)
       await video.save()
     }
 
-    const stats = await stat(videoFilePath)
-
-    videoFile.size = stats.size
-    videoFile.fps = await getVideoStreamFPS(videoFilePath)
-    videoFile.metadata = await buildFileMetadata(videoFilePath)
-
-    await createTorrentAndSetInfoHash(playlist, videoFile)
+    await createTorrentAndSetInfoHash(playlist, newVideoFile)
 
     const oldFile = await VideoFileModel.loadHLSFile({
       playlistId: playlist.id,
-      fps: videoFile.fps,
-      resolution: videoFile.resolution
+      fps: newVideoFile.fps,
+      resolution: newVideoFile.resolution
     })
 
     if (oldFile) {
@@ -111,7 +111,7 @@ export async function onHLSVideoFileTranscoding (options: {
       await oldFile.destroy()
     }
 
-    const savedVideoFile = await VideoFileModel.customUpsert(videoFile, 'streaming-playlist', undefined)
+    const savedVideoFile = await VideoFileModel.customUpsert(newVideoFile, 'streaming-playlist', undefined)
 
     await updatePlaylistAfterFileChange(video, playlist)
 
@@ -171,17 +171,8 @@ async function generateHlsPlaylistCommon (options: {
 
   await buildFFmpegVOD(job).transcode(transcodeOptions)
 
-  const newVideoFile = new VideoFileModel({
-    resolution,
-    extname: extnameUtil(videoFilename),
-    size: 0,
-    filename: videoFilename,
-    fps: -1
-  })
-
   await onHLSVideoFileTranscoding({
     video,
-    videoFile: newVideoFile,
     videoOutputPath,
     m3u8OutputPath,
     filesLockedInParent: !inputFileMutexReleaser
diff --git a/server/core/lib/transcoding/web-transcoding.ts b/server/core/lib/transcoding/web-transcoding.ts
index 8e07a5f37..22c6ef030 100644
--- a/server/core/lib/transcoding/web-transcoding.ts
+++ b/server/core/lib/transcoding/web-transcoding.ts
@@ -1,22 +1,22 @@
 import { Job } from 'bullmq'
 import { move, remove } from 'fs-extra/esm'
-import { copyFile, stat } from 'fs/promises'
+import { copyFile } from 'fs/promises'
 import { basename, join } from 'path'
-import { FileStorage } from '@peertube/peertube-models'
 import { computeOutputFPS } from '@server/helpers/ffmpeg/index.js'
 import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent.js'
 import { VideoModel } from '@server/models/video/video.js'
 import { MVideoFile, MVideoFullLight } from '@server/types/models/index.js'
-import { ffprobePromise, getVideoStreamDuration, getVideoStreamFPS, TranscodeVODOptionsType } from '@peertube/peertube-ffmpeg'
+import { getVideoStreamDuration, TranscodeVODOptionsType } from '@peertube/peertube-ffmpeg'
 import { CONFIG } from '../../initializers/config.js'
 import { VideoFileModel } from '../../models/video/video-file.js'
 import { JobQueue } from '../job-queue/index.js'
 import { generateWebVideoFilename } from '../paths.js'
-import { buildFileMetadata } from '../video-file.js'
+import { buildNewFile } from '../video-file.js'
 import { VideoPathManager } from '../video-path-manager.js'
 import { buildFFmpegVOD } from './shared/index.js'
 import { buildOriginalFileResolution } from './transcoding-resolutions.js'
 import { buildStoryboardJobIfNeeded } from '../video-jobs.js'
+import { buildAspectRatio } from '@peertube/peertube-core-utils'
 
 // Optimize the original video file and replace it. The resolution is not changed.
 export async function optimizeOriginalVideofile (options: {
@@ -62,19 +62,7 @@ export async function optimizeOriginalVideofile (options: {
         fps
       })
 
-      // Important to do this before getVideoFilename() to take in account the new filename
-      inputVideoFile.resolution = resolution
-      inputVideoFile.extname = newExtname
-      inputVideoFile.filename = generateWebVideoFilename(resolution, newExtname)
-      inputVideoFile.storage = FileStorage.FILE_SYSTEM
-
-      const { videoFile } = await onWebVideoFileTranscoding({
-        video,
-        videoFile: inputVideoFile,
-        videoOutputPath
-      })
-
-      await remove(videoInputPath)
+      const { videoFile } = await onWebVideoFileTranscoding({ video, videoOutputPath, deleteWebInputVideoFile: inputVideoFile })
 
       return { transcodeType, videoFile }
     })
@@ -104,15 +92,8 @@ export async function transcodeNewWebVideoResolution (options: {
     const file = video.getMaxQualityFile().withVideoOrPlaylist(video)
 
     const result = await VideoPathManager.Instance.makeAvailableVideoFile(file, async videoInputPath => {
-      const newVideoFile = new VideoFileModel({
-        resolution,
-        extname: newExtname,
-        filename: generateWebVideoFilename(resolution, newExtname),
-        size: 0,
-        videoId: video.id
-      })
-
-      const videoOutputPath = join(transcodeDirectory, newVideoFile.filename)
+      const filename = generateWebVideoFilename(resolution, newExtname)
+      const videoOutputPath = join(transcodeDirectory, filename)
 
       const transcodeOptions = {
         type: 'video' as 'video',
@@ -128,7 +109,7 @@ export async function transcodeNewWebVideoResolution (options: {
 
       await buildFFmpegVOD(job).transcode(transcodeOptions)
 
-      return onWebVideoFileTranscoding({ video, videoFile: newVideoFile, videoOutputPath })
+      return onWebVideoFileTranscoding({ video, videoOutputPath })
     })
 
     return result
@@ -188,20 +169,10 @@ export async function mergeAudioVideofile (options: {
         throw err
       }
 
-      // Important to do this before getVideoFilename() to take in account the new file extension
-      inputVideoFile.extname = newExtname
-      inputVideoFile.resolution = resolution
-      inputVideoFile.filename = generateWebVideoFilename(inputVideoFile.resolution, newExtname)
-
-      // ffmpeg generated a new video file, so update the video duration
-      // See https://trac.ffmpeg.org/ticket/5456
-      video.duration = await getVideoStreamDuration(videoOutputPath)
-      await video.save()
-
-      return onWebVideoFileTranscoding({
+      await onWebVideoFileTranscoding({
         video,
-        videoFile: inputVideoFile,
         videoOutputPath,
+        deleteWebInputVideoFile: inputVideoFile,
         wasAudioFile: true
       })
     })
@@ -214,36 +185,42 @@ export async function mergeAudioVideofile (options: {
 
 export async function onWebVideoFileTranscoding (options: {
   video: MVideoFullLight
-  videoFile: MVideoFile
   videoOutputPath: string
   wasAudioFile?: boolean // default false
+  deleteWebInputVideoFile?: MVideoFile
 }) {
-  const { video, videoFile, videoOutputPath, wasAudioFile } = options
+  const { video, videoOutputPath, wasAudioFile, deleteWebInputVideoFile } = options
 
   const mutexReleaser = await VideoPathManager.Instance.lockFiles(video.uuid)
 
+  const videoFile = await buildNewFile({ mode: 'web-video', path: videoOutputPath })
+  videoFile.videoId = video.id
+
   try {
     await video.reload()
 
+    // ffmpeg generated a new video file, so update the video duration
+    // See https://trac.ffmpeg.org/ticket/5456
+    if (wasAudioFile) {
+      video.duration = await getVideoStreamDuration(videoOutputPath)
+      video.aspectRatio = buildAspectRatio({ width: videoFile.width, height: videoFile.height })
+      await video.save()
+    }
+
     const outputPath = VideoPathManager.Instance.getFSVideoFileOutputPath(video, videoFile)
 
-    const stats = await stat(videoOutputPath)
-
-    const probe = await ffprobePromise(videoOutputPath)
-    const fps = await getVideoStreamFPS(videoOutputPath, probe)
-    const metadata = await buildFileMetadata(videoOutputPath, probe)
-
     await move(videoOutputPath, outputPath, { overwrite: true })
 
-    videoFile.size = stats.size
-    videoFile.fps = fps
-    videoFile.metadata = metadata
-
     await createTorrentAndSetInfoHash(video, videoFile)
 
     const oldFile = await VideoFileModel.loadWebVideoFile({ videoId: video.id, fps: videoFile.fps, resolution: videoFile.resolution })
     if (oldFile) await video.removeWebVideoFile(oldFile)
 
+    if (deleteWebInputVideoFile) {
+      await video.removeWebVideoFile(deleteWebInputVideoFile)
+      await deleteWebInputVideoFile.destroy()
+    }
+
     await VideoFileModel.customUpsert(videoFile, 'video', undefined)
     video.VideoFiles = await video.$get('VideoFiles')
 
diff --git a/server/core/lib/video-file.ts b/server/core/lib/video-file.ts
index 326dff75e..f5463363e 100644
--- a/server/core/lib/video-file.ts
+++ b/server/core/lib/video-file.ts
@@ -29,8 +29,11 @@ async function buildNewFile (options: {
   if (await isAudioFile(path, probe)) {
     videoFile.resolution = VideoResolution.H_NOVIDEO
   } else {
+    const dimensions = await getVideoStreamDimensionsInfo(path, probe)
     videoFile.fps = await getVideoStreamFPS(path, probe)
-    videoFile.resolution = (await getVideoStreamDimensionsInfo(path, probe)).resolution
+    videoFile.resolution = dimensions.resolution
+    videoFile.width = dimensions.width
+    videoFile.height = dimensions.height
   }
 
   videoFile.filename = mode === 'web-video'
diff --git a/server/core/lib/video-studio.ts b/server/core/lib/video-studio.ts
index 6e118bd00..09ccaf14b 100644
--- a/server/core/lib/video-studio.ts
+++ b/server/core/lib/video-studio.ts
@@ -12,6 +12,7 @@ import { getTranscodingJobPriority } from './transcoding/transcoding-priority.js
 import { buildNewFile, removeHLSPlaylist, removeWebVideoFile } from './video-file.js'
 import { VideoPathManager } from './video-path-manager.js'
 import { buildStoryboardJobIfNeeded } from './video-jobs.js'
+import { buildAspectRatio } from '@peertube/peertube-core-utils'
 
 const lTags = loggerTagsFactory('video-studio')
 
@@ -104,6 +105,7 @@ export async function onVideoStudioEnded (options: {
   await newFile.save()
 
   video.duration = await getVideoStreamDuration(outputPath)
+  video.aspectRatio = buildAspectRatio({ width: newFile.width, height: newFile.height })
   await video.save()
 
   return JobQueue.Instance.createSequentialJobFlow(
diff --git a/server/core/models/server/plugin.ts b/server/core/models/server/plugin.ts
index 500e59e33..13ca809ef 100644
--- a/server/core/models/server/plugin.ts
+++ b/server/core/models/server/plugin.ts
@@ -18,6 +18,7 @@ import {
   isPluginTypeValid
 } from '../../helpers/custom-validators/plugins.js'
 import { SequelizeModel, getSort, throwIfNotValid } from '../shared/index.js'
+import { logger } from '@server/helpers/logger.js'
 
 @DefaultScope(() => ({
   attributes: {
@@ -173,6 +174,7 @@ export class PluginModel extends SequelizeModel<PluginModel> {
             result[name] = p.settings[name]
           }
         }
+        logger.error('internal', { result })
 
         return result
       })
diff --git a/server/core/models/video/formatter/video-activity-pub-format.ts b/server/core/models/video/formatter/video-activity-pub-format.ts
index bfa28cbca..a95fbb3e3 100644
--- a/server/core/models/video/formatter/video-activity-pub-format.ts
+++ b/server/core/models/video/formatter/video-activity-pub-format.ts
@@ -88,6 +88,8 @@ export function videoModelToActivityPubObject (video: MVideoAP): VideoObject {
 
     preview: buildPreviewAPAttribute(video),
 
+    aspectRatio: video.aspectRatio,
+
     url,
 
     likes: getLocalVideoLikesActivityPubUrl(video),
@@ -185,7 +187,8 @@ function buildVideoFileUrls (options: {
       rel: [ 'metadata', fileAP.mediaType ],
       mediaType: 'application/json' as 'application/json',
       href: getLocalVideoFileMetadataUrl(video, file),
-      height: file.resolution,
+      height: file.height || file.resolution,
+      width: file.width,
       fps: file.fps
     })
 
@@ -194,14 +197,18 @@ function buildVideoFileUrls (options: {
         type: 'Link',
         mediaType: 'application/x-bittorrent' as 'application/x-bittorrent',
         href: file.getTorrentUrl(),
-        height: file.resolution
+        height: file.height || file.resolution,
+        width: file.width,
+        fps: file.fps
       })
 
       urls.push({
         type: 'Link',
         mediaType: 'application/x-bittorrent;x-scheme-handler/magnet' as 'application/x-bittorrent;x-scheme-handler/magnet',
         href: generateMagnetUri(video, file, trackerUrls),
-        height: file.resolution
+        height: file.height || file.resolution,
+        width: file.width,
+        fps: file.fps
       })
     }
   }
diff --git a/server/core/models/video/formatter/video-api-format.ts b/server/core/models/video/formatter/video-api-format.ts
index a4bb0b733..7e6bcb431 100644
--- a/server/core/models/video/formatter/video-api-format.ts
+++ b/server/core/models/video/formatter/video-api-format.ts
@@ -89,6 +89,8 @@ export function videoModelToFormattedJSON (video: MVideoFormattable, options: Vi
     isLocal: video.isOwned(),
     duration: video.duration,
 
+    aspectRatio: video.aspectRatio,
+
     views: video.views,
     viewers: VideoViewsManager.Instance.getTotalViewersOf(video),
 
@@ -214,6 +216,9 @@ export function videoFilesModelToFormattedJSON (
             : `${videoFile.resolution}p`
         },
 
+        width: videoFile.width,
+        height: videoFile.height,
+
         magnetUri: includeMagnet && videoFile.hasTorrent()
           ? generateMagnetUri(video, videoFile, trackerUrls)
           : undefined,
diff --git a/server/core/models/video/sql/video/shared/video-table-attributes.ts b/server/core/models/video/sql/video/shared/video-table-attributes.ts
index f13fcf7ce..b6222cebb 100644
--- a/server/core/models/video/sql/video/shared/video-table-attributes.ts
+++ b/server/core/models/video/sql/video/shared/video-table-attributes.ts
@@ -88,6 +88,8 @@ export class VideoTableAttributes {
       'metadataUrl',
       'videoStreamingPlaylistId',
       'videoId',
+      'width',
+      'height',
       'storage'
     ]
   }
@@ -255,6 +257,7 @@ export class VideoTableAttributes {
       'dislikes',
       'remote',
       'isLive',
+      'aspectRatio',
       'url',
       'commentsEnabled',
       'downloadEnabled',
diff --git a/server/core/models/video/video-file.ts b/server/core/models/video/video-file.ts
index dbe9ab5d9..31b2323cb 100644
--- a/server/core/models/video/video-file.ts
+++ b/server/core/models/video/video-file.ts
@@ -167,6 +167,14 @@ export class VideoFileModel extends SequelizeModel<VideoFileModel> {
   @Column
   resolution: number
 
+  @AllowNull(true)
+  @Column
+  width: number
+
+  @AllowNull(true)
+  @Column
+  height: number
+
   @AllowNull(false)
   @Is('VideoFileSize', value => throwIfNotValid(value, isVideoFileSizeValid, 'size'))
   @Column(DataType.BIGINT)
@@ -640,7 +648,8 @@ export class VideoFileModel extends SequelizeModel<VideoFileModel> {
       type: 'Link',
       mediaType: mimeType as ActivityVideoUrlObject['mediaType'],
       href: this.getFileUrl(video),
-      height: this.resolution,
+      height: this.height || this.resolution,
+      width: this.width,
       size: this.size,
       fps: this.fps
     }
diff --git a/server/core/models/video/video.ts b/server/core/models/video/video.ts
index 88af4f429..530db47b0 100644
--- a/server/core/models/video/video.ts
+++ b/server/core/models/video/video.ts
@@ -565,6 +565,10 @@ export class VideoModel extends SequelizeModel<VideoModel> {
   @Column
   state: VideoStateType
 
+  @AllowNull(true)
+  @Column(DataType.FLOAT)
+  aspectRatio: number
+
   // We already have the information in videoSource table for local videos, but we prefer to normalize it for performance
   // And also to store the info from remote instances
   @AllowNull(true)
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml
index 84ac053cb..983b65c13 100644
--- a/support/doc/api/openapi.yaml
+++ b/support/doc/api/openapi.yaml
@@ -2086,7 +2086,7 @@ paths:
 
   /api/v1/users/me/videos:
     get:
-      summary: Get videos of my user
+      summary: List videos of my user
       security:
         - OAuth2:
           - user
@@ -7560,6 +7560,12 @@ components:
         fps:
           type: number
           description: Frames per second of the video file
+        width:
+          type: number
+          description: "**PeerTube >= 6.1** Video stream width"
+        height:
+          type: number
+          description: "**PeerTube >= 6.1** Video stream height"
         metadataUrl:
           type: string
           format: url
@@ -7676,6 +7682,11 @@ components:
           example: 1419
           format: seconds
           description: duration of the video in seconds
+        aspectRatio:
+          type: number
+          format: float
+          example: 1.778
+          description: "**PeerTube >= 6.1** Aspect ratio of the video stream"
         isLocal:
           type: boolean
         name: