diff --git a/client/.browserslistrc b/client/.browserslistrc
index 9eb6a61de7c..cdc51d7ada5 100644
--- a/client/.browserslistrc
+++ b/client/.browserslistrc
@@ -1,4 +1,4 @@
last 1 Chrome version
last 2 Edge major versions
Firefox ESR
-ios_saf >= 13.1
+ios_saf >= 14
diff --git a/client/.eslintrc.json b/client/.eslintrc.json
index d00e6e7abbc..709aa79d1a8 100644
--- a/client/.eslintrc.json
+++ b/client/.eslintrc.json
@@ -163,7 +163,8 @@
"@typescript-eslint/unbound-method": [
"error",
{ "ignoreStatic": true }
- ]
+ ],
+ "import/no-named-default": "off"
}
},
{
diff --git a/client/.gitignore b/client/.gitignore
index 6523ad810a5..04c0e93f135 100644
--- a/client/.gitignore
+++ b/client/.gitignore
@@ -12,6 +12,8 @@
/e2e/local.log
/e2e/browserstack.err
/e2e/screenshots
+/src/standalone/player/build
+/src/standalone/player/dist
/src/standalone/embed-player-api/build
/src/standalone/embed-player-api/dist
/e2e/logs
diff --git a/client/angular.json b/client/angular.json
index 82c4ad21704..8c0d6f14481 100644
--- a/client/angular.json
+++ b/client/angular.json
@@ -183,7 +183,10 @@
"includePaths": [
"src/sass/include",
"."
- ]
+ ],
+ "sass": {
+ "silenceDeprecations": [ "import", "mixed-decls", "color-functions", "global-builtin" ]
+ }
},
"assets": [
"src/assets/images",
@@ -212,7 +215,9 @@
"is-plain-object",
"parse-srcset",
"deepmerge",
- "core-js/features/reflect"
+ "core-js/features/reflect",
+ "hammerjs",
+ "jschannel"
],
"scripts": [],
"extractLicenses": false,
@@ -241,7 +246,7 @@
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
- "maximumError": "100kb"
+ "maximumError": "120kb"
}
],
"fileReplacements": [
diff --git a/client/e2e/tsconfig.json b/client/e2e/tsconfig.json
index af776ebd32e..f5958a4b236 100644
--- a/client/e2e/tsconfig.json
+++ b/client/e2e/tsconfig.json
@@ -5,7 +5,7 @@
"noImplicitAny": false,
"esModuleInterop": true,
"module": "commonjs",
- "target": "ES2015",
+ "target": "ES2018",
"typeRoots": [
"../node_modules/@types",
"../node_modules"
diff --git a/client/package.json b/client/package.json
index ae3b47d645b..d9fce706bc7 100644
--- a/client/package.json
+++ b/client/package.json
@@ -24,10 +24,13 @@
"net": false,
"stream": false,
"os": false,
+ "http": false,
+ "dgram": false,
"util": false
},
"workspaces": [
- "../packages/*"
+ "../packages/*",
+ "./src/standalone/player"
],
"typings": "*.d.ts",
"devDependencies": {
@@ -55,8 +58,6 @@
"@ngx-loading-bar/http-client": "^7.0.0",
"@ngx-loading-bar/router": "^7.0.0",
"@peertube/maildev": "^1.2.0",
- "@peertube/p2p-media-loader-core": "^1.0.20",
- "@peertube/p2p-media-loader-hlsjs": "^1.0.20",
"@peertube/xliffmerge": "^2.0.3",
"@plussub/srt-vtt-parser": "^2.0.5",
"@popperjs/core": "^2.11.5",
@@ -103,8 +104,11 @@
"markdown-it": "14.1.0",
"markdown-it-emoji": "^3.0.0",
"ngx-uploadx": "^7.0.0",
+ "p2p-media-loader-core": "^2.1.2",
+ "p2p-media-loader-hlsjs": "^2.1.2",
"primeng": "^17",
"rxjs": "^7.3.0",
+ "sass-embedded": "^1.83.4",
"sha.js": "^2.4.11",
"socket.io-client": "^4.5.4",
"stylelint": "^16.2.1",
@@ -115,9 +119,9 @@
"tslib": "^2.4.0",
"typescript": "~5.7.3",
"video.js": "^7.19.2",
- "vite": "^5.3.1",
- "vite-plugin-checker": "^0.7.2",
- "vite-plugin-node-polyfills": "^0.22.0",
+ "vite": "^6.0.11",
+ "vite-plugin-checker": "^0.8.0",
+ "vite-plugin-node-polyfills": "^0.23.0",
"zone.js": "~0.15.0"
},
"dependencies": {}
diff --git a/client/src/app/+videos/+video-watch/player-styles.component.scss b/client/src/app/+videos/+video-watch/player-styles.component.scss
index c0befc10a74..d2b386a5b47 100644
--- a/client/src/app/+videos/+video-watch/player-styles.component.scss
+++ b/client/src/app/+videos/+video-watch/player-styles.component.scss
@@ -1,5 +1 @@
-@use 'node_modules/video.js/dist/video-js';
-
-$assets-path: '../../assets/';
-
-@use '../../../sass/player/index';
+@use '../../../standalone/player/build/peertube-player.css';
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts
index ca49564396d..6f4c3fa65c6 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/+videos/+video-watch/video-watch.component.ts
@@ -47,16 +47,18 @@ import { logger } from '@root-helpers/logger'
import { isP2PEnabled, videoRequiresFileToken, videoRequiresUserAuth } from '@root-helpers/video'
import debug from 'debug'
import { forkJoin, map, Observable, of, Subscription, switchMap } from 'rxjs'
+import { environment } from '../../../environments/environment'
import {
+ cleanupVideoWatch,
+ getStoredTheater,
+ getStoredVideoWatchHistory,
HLSOptions,
PeerTubePlayer,
PeerTubePlayerConstructorOptions,
PeerTubePlayerLoadOptions,
PlayerMode,
videojs
-} from '../../../assets/player'
-import { cleanupVideoWatch, getStoredTheater, getStoredVideoWatchHistory } from '../../../assets/player/peertube-player-local-storage'
-import { environment } from '../../../environments/environment'
+} from '@peertube/player'
import { DateToggleComponent } from '../../shared/shared-main/date/date-toggle.component'
import { PluginPlaceholderComponent } from '../../shared/shared-main/plugins/plugin-placeholder.component'
import { VideoViewsCounterComponent } from '../../shared/shared-video/video-views-counter.component'
diff --git a/client/src/assets/player/index.ts b/client/src/assets/player/index.ts
deleted file mode 100644
index d34188ea755..00000000000
--- a/client/src/assets/player/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export * from './peertube-player'
-export * from './types'
diff --git a/client/src/root-helpers/plugins-manager.ts b/client/src/root-helpers/plugins-manager.ts
index b11af1511f1..c82836f9fc3 100644
--- a/client/src/root-helpers/plugins-manager.ts
+++ b/client/src/root-helpers/plugins-manager.ts
@@ -2,7 +2,7 @@
import debug from 'debug'
import { firstValueFrom, ReplaySubject } from 'rxjs'
import { first, shareReplay } from 'rxjs/operators'
-import { RegisterClientHelpers } from 'src/types/register-client-option.model'
+import { RegisterClientHelpers } from '../types/register-client-option.model'
import { getExternalAuthHref, getHookType, internalRunHook } from '@peertube/peertube-core-utils'
import {
ClientDoAction,
@@ -83,6 +83,7 @@ class PluginsManager {
private readonly onFormFields: OnFormFields
private readonly onSettingsScripts: OnSettingsScripts
private readonly onClientRoute: OnClientRoute
+ private readonly backendUrl: string
constructor (options: {
doAction?: ClientDoAction
@@ -90,12 +91,14 @@ class PluginsManager {
onFormFields?: OnFormFields
onSettingsScripts?: OnSettingsScripts
onClientRoute?: OnClientRoute
+ backendUrl?: string
}) {
this.doAction = options.doAction
this.peertubeHelpersFactory = options.peertubeHelpersFactory
this.onFormFields = options.onFormFields
this.onSettingsScripts = options.onSettingsScripts
this.onClientRoute = options.onClientRoute
+ this.backendUrl = options.backendUrl
}
static getPluginPathPrefix (isTheme: boolean) {
@@ -281,7 +284,7 @@ class PluginsManager {
logger.info(`Loading script ${clientScript.script} of plugin ${plugin.name}`)
- const absURL = (environment.apiUrl || window.location.origin) + clientScript.script
+ const absURL = (this.backendUrl || environment.apiUrl || window.location.origin) + clientScript.script
return dynamicImport(absURL)
.then((script: ClientScript) => {
return script.register({
diff --git a/client/src/assets/player/translations-manager.ts b/client/src/root-helpers/translations-manager.ts
similarity index 100%
rename from client/src/assets/player/translations-manager.ts
rename to client/src/root-helpers/translations-manager.ts
diff --git a/client/src/standalone/build-tools/vite-utils.ts b/client/src/standalone/build-tools/vite-utils.ts
new file mode 100644
index 00000000000..bf366659cfd
--- /dev/null
+++ b/client/src/standalone/build-tools/vite-utils.ts
@@ -0,0 +1,21 @@
+import { resolve } from 'path'
+
+export function getCSSConfig (root: string) {
+ return {
+ preprocessorOptions: {
+ scss: {
+ api: 'modern-compiler',
+ loadPaths: [ resolve(root, './src/sass/include') ],
+ // FIXME: Wait for bootstrap upgrade that fixes deprecated sass utils
+ silenceDeprecations: [ 'import', 'mixed-decls', 'color-functions', 'global-builtin' ]
+ }
+ }
+ }
+}
+
+export function getAliasConfig (root: string) {
+ return [
+ { find: /^video.js$/, replacement: resolve(root, './node_modules/video.js/core.js') },
+ { find: '@root-helpers', replacement: resolve(root, './src/root-helpers') }
+ ]
+}
diff --git a/client/src/standalone/player/package.json b/client/src/standalone/player/package.json
new file mode 100644
index 00000000000..940ccb746f9
--- /dev/null
+++ b/client/src/standalone/player/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "@peertube/player",
+ "private": false,
+ "version": "0.0.0",
+ "scripts": {
+ "build": "rm -rf ./build && ../../../node_modules/.bin/vite build --mode production --config ./vite.config.mjs",
+ "dev": "../../../node_modules/.bin/vite build --mode dev --watch --config ./vite.config.mjs"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/Chocobozzz/PeerTube.git"
+ },
+ "keywords": [
+ "peertube",
+ "embed"
+ ],
+ "main": "./build/peertube-player.js",
+ "exports": {
+ ".": "./build/peertube-player.js"
+ },
+ "types": "./src/index.ts",
+ "author": "Chocobozzz",
+ "license": "AGPL-3.0",
+ "type": "module",
+ "sideEffects": true,
+ "bugs": {
+ "url": "https://github.com/Chocobozzz/PeerTube/issues"
+ },
+ "homepage": "https://github.com/Chocobozzz/PeerTube#readme",
+ "dependencies": {}
+}
diff --git a/client/src/standalone/player/src/index.ts b/client/src/standalone/player/src/index.ts
new file mode 100644
index 00000000000..66e3e149795
--- /dev/null
+++ b/client/src/standalone/player/src/index.ts
@@ -0,0 +1,5 @@
+export * from './peertube-player'
+export * from './peertube-player-local-storage'
+export * from './types'
+
+import './sass/player.scss'
diff --git a/client/src/assets/player/peertube-player-local-storage.ts b/client/src/standalone/player/src/peertube-player-local-storage.ts
similarity index 100%
rename from client/src/assets/player/peertube-player-local-storage.ts
rename to client/src/standalone/player/src/peertube-player-local-storage.ts
diff --git a/client/src/assets/player/peertube-player.ts b/client/src/standalone/player/src/peertube-player.ts
similarity index 99%
rename from client/src/assets/player/peertube-player.ts
rename to client/src/standalone/player/src/peertube-player.ts
index 2c4108bbb52..182eb47cccd 100644
--- a/client/src/assets/player/peertube-player.ts
+++ b/client/src/standalone/player/src/peertube-player.ts
@@ -31,6 +31,8 @@ import './shared/metrics/metrics-plugin'
import './shared/p2p-media-loader/hls-plugin'
import './shared/p2p-media-loader/p2p-media-loader-plugin'
import './shared/web-video/web-video-plugin'
+import './shared/dock/peertube-dock-component'
+import './shared/dock/peertube-dock-plugin'
import videojs, { VideoJsPlayer } from 'video.js'
import { logger } from '@root-helpers/logger'
import { PluginsManager } from '@root-helpers/plugins-manager'
@@ -40,7 +42,7 @@ import { isMobile } from '@root-helpers/web-browser'
import { buildVideoLink, decorateVideoLink, isDefaultLocale, pick } from '@peertube/peertube-core-utils'
import { saveAverageBandwidth } from './peertube-player-local-storage'
import { ControlBarOptionsBuilder, HLSOptionsBuilder, WebVideoOptionsBuilder } from './shared/player-options-builder'
-import { TranslationsManager } from './translations-manager'
+import { TranslationsManager } from '@root-helpers/translations-manager'
import { PeerTubePlayerConstructorOptions, PeerTubePlayerLoadOptions, PlayerNetworkInfo, VideoJSPluginOptions } from './types'
// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
diff --git a/client/src/standalone/player/src/sass/player.scss b/client/src/standalone/player/src/sass/player.scss
new file mode 100644
index 00000000000..30d2493bca2
--- /dev/null
+++ b/client/src/standalone/player/src/sass/player.scss
@@ -0,0 +1,2 @@
+@use '../../../node_modules/video.js/dist/video-js';
+@use './shared/index.scss';
diff --git a/client/src/sass/player/_player-variables.scss b/client/src/standalone/player/src/sass/shared/_player-variables.scss
similarity index 93%
rename from client/src/sass/player/_player-variables.scss
rename to client/src/standalone/player/src/sass/shared/_player-variables.scss
index 8691bf6b2bd..9e0f41363fd 100644
--- a/client/src/sass/player/_player-variables.scss
+++ b/client/src/standalone/player/src/sass/shared/_player-variables.scss
@@ -22,5 +22,3 @@ $control-bar-total-height: $control-bar-height - $control-bar-slider-top;
$progress-margin: 10px;
$dock-padding: 20px;
-
-$assets-path: '../../assets/' !default;
diff --git a/client/src/sass/player/bezels.scss b/client/src/standalone/player/src/sass/shared/bezels.scss
similarity index 100%
rename from client/src/sass/player/bezels.scss
rename to client/src/standalone/player/src/sass/shared/bezels.scss
diff --git a/client/src/sass/player/context-menu.scss b/client/src/standalone/player/src/sass/shared/context-menu.scss
similarity index 89%
rename from client/src/sass/player/context-menu.scss
rename to client/src/standalone/player/src/sass/shared/context-menu.scss
index f5b051be252..84f5928d169 100644
--- a/client/src/sass/player/context-menu.scss
+++ b/client/src/standalone/player/src/sass/shared/context-menu.scss
@@ -50,8 +50,8 @@ $context-menu-width: 350px;
@each $icon in $icons {
&[class$="-#{$icon}"] {
- mask-image: url('#{$assets-path}/player/images/#{$icon}.svg');
- -webkit-mask-image: url('#{$assets-path}/player/images/#{$icon}.svg');
+ mask-image: url('./svg/#{$icon}.svg');
+ -webkit-mask-image: url('./svg/#{$icon}.svg');
}
}
diff --git a/client/src/sass/player/control-bar.scss b/client/src/standalone/player/src/sass/shared/control-bar.scss
similarity index 94%
rename from client/src/sass/player/control-bar.scss
rename to client/src/standalone/player/src/sass/shared/control-bar.scss
index af54d0ccc97..14d7b1c8b84 100644
--- a/client/src/sass/player/control-bar.scss
+++ b/client/src/standalone/player/src/sass/shared/control-bar.scss
@@ -270,11 +270,11 @@ $chapter-marker-size: 9px;
@include margin-right(2px);
&.icon-download {
- background-image: url('#{$assets-path}/player/images/arrow-down.svg');
+ background-image: url('./svg/arrow-down.svg');
}
&.icon-upload {
- background-image: url('#{$assets-path}/player/images/arrow-up.svg');
+ background-image: url('./svg/arrow-up.svg');
}
}
}
@@ -291,8 +291,8 @@ $chapter-marker-size: 9px;
.icon {
&.icon-next,
&.icon-previous {
- mask-image: url('#{$assets-path}/player/images/next.svg');
- -webkit-mask-image: url('#{$assets-path}/player/images/next.svg');
+ mask-image: url('./svg/next.svg');
+ -webkit-mask-image: url('./svg/next.svg');
mask-size: cover;
-webkit-mask-size: cover;
@@ -319,7 +319,7 @@ $chapter-marker-size: 9px;
width: $control-bar-icon-size;
height: $control-bar-icon-size;
vertical-align: middle;
- background: url('#{$assets-path}/player/images/volume.svg') no-repeat;
+ background: url('./svg/volume.svg') no-repeat;
background-size: contain;
&::before {
@@ -328,7 +328,7 @@ $chapter-marker-size: 9px;
}
&.vjs-vol-0 .vjs-icon-placeholder {
- background: url('#{$assets-path}/player/images/volume-mute.svg') no-repeat;
+ background: url('./svg/volume-mute.svg') no-repeat;
background-size: contain;
}
}
@@ -415,7 +415,7 @@ $chapter-marker-size: 9px;
height: $control-bar-icon-size - 4px;
width: $control-bar-icon-size - 4px;
vertical-align: middle;
- background: url('#{$assets-path}/player/images/settings.svg') no-repeat;
+ background: url('./svg/settings.svg') no-repeat;
background-size: contain;
&::before {
@@ -448,7 +448,7 @@ $chapter-marker-size: 9px;
width: $control-bar-icon-size - 4px;
height: $control-bar-icon-size - 4px;
vertical-align: middle;
- background: url('#{$assets-path}/player/images/theater.svg') no-repeat;
+ background: url('./svg/theater.svg') no-repeat;
background-size: contain;
&::before {
@@ -493,7 +493,7 @@ $chapter-marker-size: 9px;
width: $control-bar-icon-size;
height: $control-bar-icon-size;
vertical-align: middle;
- background: url('#{$assets-path}/player/images/fullscreen.svg') no-repeat;
+ background: url('./svg/fullscreen.svg') no-repeat;
background-size: contain;
&::before {
@@ -515,14 +515,6 @@ $chapter-marker-size: 9px;
.vjs-theater-control {
display: none;
}
-
- .vjs-peertube {
- .icon,
- .download-speed-text,
- .upload-speed-text {
- display: none !important;
- }
- }
}
.video-js.vjs-peertube-skin.vjs-size-570 .vjs-control-bar {
@@ -540,6 +532,12 @@ $chapter-marker-size: 9px;
.vjs-peertube-displayed {
display: none !important;
}
+
+ .icon,
+ .download-speed-text,
+ .upload-speed-text {
+ display: none !important;
+ }
}
.vjs-peertube-link {
diff --git a/client/src/sass/player/dock.scss b/client/src/standalone/player/src/sass/shared/dock.scss
similarity index 100%
rename from client/src/sass/player/dock.scss
rename to client/src/standalone/player/src/sass/shared/dock.scss
diff --git a/client/src/sass/player/index.scss b/client/src/standalone/player/src/sass/shared/index.scss
similarity index 100%
rename from client/src/sass/player/index.scss
rename to client/src/standalone/player/src/sass/shared/index.scss
diff --git a/client/src/sass/player/mobile.scss b/client/src/standalone/player/src/sass/shared/mobile.scss
similarity index 100%
rename from client/src/sass/player/mobile.scss
rename to client/src/standalone/player/src/sass/shared/mobile.scss
diff --git a/client/src/sass/player/offline-notification.scss b/client/src/standalone/player/src/sass/shared/offline-notification.scss
similarity index 100%
rename from client/src/sass/player/offline-notification.scss
rename to client/src/standalone/player/src/sass/shared/offline-notification.scss
diff --git a/client/src/sass/player/peertube-skin.scss b/client/src/standalone/player/src/sass/shared/peertube-skin.scss
similarity index 98%
rename from client/src/sass/player/peertube-skin.scss
rename to client/src/standalone/player/src/sass/shared/peertube-skin.scss
index ea9f3e3354d..381bde83a08 100644
--- a/client/src/sass/player/peertube-skin.scss
+++ b/client/src/standalone/player/src/sass/shared/peertube-skin.scss
@@ -60,7 +60,7 @@ body {
.vjs-icon-placeholder::before {
content: '';
- background-image: url('#{$assets-path}/player/images/big-play-button.svg');
+ background-image: url('./svg/big-play-button.svg');
@include big-play-button-triangle-size(45px);
}
diff --git a/client/src/sass/player/playlist.scss b/client/src/standalone/player/src/sass/shared/playlist.scss
similarity index 91%
rename from client/src/sass/player/playlist.scss
rename to client/src/standalone/player/src/sass/shared/playlist.scss
index c3e571b003a..f39a8463b1a 100644
--- a/client/src/sass/player/playlist.scss
+++ b/client/src/standalone/player/src/sass/shared/playlist.scss
@@ -44,8 +44,8 @@ $playlist-menu-width: 350px;
}
.cross {
- mask-image: url('#{$assets-path}/images/feather/x.svg');
- -webkit-mask-image: url('#{$assets-path}/images/feather/x.svg');
+ mask-image: url('./svg/x.svg');
+ -webkit-mask-image: url('./svg/x.svg');
mask-size: cover;
-webkit-mask-size: cover;
@@ -92,8 +92,8 @@ $playlist-menu-width: 350px;
}
.vjs-playlist-icon {
- mask-image: url('#{$assets-path}/images/feather/playlists.svg');
- -webkit-mask-image: url('#{$assets-path}/images/feather/playlists.svg');
+ mask-image: url('./svg/playlists.svg');
+ -webkit-mask-image: url('./svg/playlists.svg');
mask-size: cover;
-webkit-mask-size: cover;
diff --git a/client/src/sass/player/settings-menu.scss b/client/src/standalone/player/src/sass/shared/settings-menu.scss
similarity index 97%
rename from client/src/sass/player/settings-menu.scss
rename to client/src/standalone/player/src/sass/shared/settings-menu.scss
index d2095e85b62..0353c0b3121 100644
--- a/client/src/sass/player/settings-menu.scss
+++ b/client/src/standalone/player/src/sass/shared/settings-menu.scss
@@ -145,7 +145,7 @@ $setting-transition-easing: ease-out;
position: absolute;
content: ' ';
margin-top: 1px;
- background-image: url('#{$assets-path}/player/images/tick-white.svg');
+ background-image: url('./svg/tick-white.svg');
@include icon(15px);
@include left(15px);
diff --git a/client/src/sass/player/spinner.scss b/client/src/standalone/player/src/sass/shared/spinner.scss
similarity index 100%
rename from client/src/sass/player/spinner.scss
rename to client/src/standalone/player/src/sass/shared/spinner.scss
diff --git a/client/src/sass/player/stats.scss b/client/src/standalone/player/src/sass/shared/stats.scss
similarity index 100%
rename from client/src/sass/player/stats.scss
rename to client/src/standalone/player/src/sass/shared/stats.scss
diff --git a/client/src/sass/player/storyboard.scss b/client/src/standalone/player/src/sass/shared/storyboard.scss
similarity index 100%
rename from client/src/sass/player/storyboard.scss
rename to client/src/standalone/player/src/sass/shared/storyboard.scss
diff --git a/client/src/sass/player/upnext.scss b/client/src/standalone/player/src/sass/shared/upnext.scss
similarity index 100%
rename from client/src/sass/player/upnext.scss
rename to client/src/standalone/player/src/sass/shared/upnext.scss
diff --git a/client/src/assets/player/images/arrow-down.svg b/client/src/standalone/player/src/sass/svg/arrow-down.svg
similarity index 100%
rename from client/src/assets/player/images/arrow-down.svg
rename to client/src/standalone/player/src/sass/svg/arrow-down.svg
diff --git a/client/src/assets/player/images/arrow-up.svg b/client/src/standalone/player/src/sass/svg/arrow-up.svg
similarity index 100%
rename from client/src/assets/player/images/arrow-up.svg
rename to client/src/standalone/player/src/sass/svg/arrow-up.svg
diff --git a/client/src/assets/player/images/big-play-button.svg b/client/src/standalone/player/src/sass/svg/big-play-button.svg
similarity index 100%
rename from client/src/assets/player/images/big-play-button.svg
rename to client/src/standalone/player/src/sass/svg/big-play-button.svg
diff --git a/client/src/assets/player/images/code.svg b/client/src/standalone/player/src/sass/svg/code.svg
similarity index 100%
rename from client/src/assets/player/images/code.svg
rename to client/src/standalone/player/src/sass/svg/code.svg
diff --git a/client/src/assets/player/images/fullscreen.svg b/client/src/standalone/player/src/sass/svg/fullscreen.svg
similarity index 100%
rename from client/src/assets/player/images/fullscreen.svg
rename to client/src/standalone/player/src/sass/svg/fullscreen.svg
diff --git a/client/src/assets/player/images/info.svg b/client/src/standalone/player/src/sass/svg/info.svg
similarity index 100%
rename from client/src/assets/player/images/info.svg
rename to client/src/standalone/player/src/sass/svg/info.svg
diff --git a/client/src/assets/player/images/link-2.svg b/client/src/standalone/player/src/sass/svg/link-2.svg
similarity index 100%
rename from client/src/assets/player/images/link-2.svg
rename to client/src/standalone/player/src/sass/svg/link-2.svg
diff --git a/client/src/assets/player/images/next.svg b/client/src/standalone/player/src/sass/svg/next.svg
similarity index 100%
rename from client/src/assets/player/images/next.svg
rename to client/src/standalone/player/src/sass/svg/next.svg
diff --git a/client/src/standalone/player/src/sass/svg/playlists.svg b/client/src/standalone/player/src/sass/svg/playlists.svg
new file mode 100644
index 00000000000..247c073f0ec
--- /dev/null
+++ b/client/src/standalone/player/src/sass/svg/playlists.svg
@@ -0,0 +1,77 @@
+
+
diff --git a/client/src/assets/player/images/repeat.svg b/client/src/standalone/player/src/sass/svg/repeat.svg
similarity index 100%
rename from client/src/assets/player/images/repeat.svg
rename to client/src/standalone/player/src/sass/svg/repeat.svg
diff --git a/client/src/assets/player/images/settings.svg b/client/src/standalone/player/src/sass/svg/settings.svg
similarity index 100%
rename from client/src/assets/player/images/settings.svg
rename to client/src/standalone/player/src/sass/svg/settings.svg
diff --git a/client/src/assets/player/images/theater.svg b/client/src/standalone/player/src/sass/svg/theater.svg
similarity index 100%
rename from client/src/assets/player/images/theater.svg
rename to client/src/standalone/player/src/sass/svg/theater.svg
diff --git a/client/src/assets/player/images/tick-white.svg b/client/src/standalone/player/src/sass/svg/tick-white.svg
similarity index 100%
rename from client/src/assets/player/images/tick-white.svg
rename to client/src/standalone/player/src/sass/svg/tick-white.svg
diff --git a/client/src/assets/player/images/volume-mute.svg b/client/src/standalone/player/src/sass/svg/volume-mute.svg
similarity index 100%
rename from client/src/assets/player/images/volume-mute.svg
rename to client/src/standalone/player/src/sass/svg/volume-mute.svg
diff --git a/client/src/assets/player/images/volume.svg b/client/src/standalone/player/src/sass/svg/volume.svg
similarity index 100%
rename from client/src/assets/player/images/volume.svg
rename to client/src/standalone/player/src/sass/svg/volume.svg
diff --git a/client/src/standalone/player/src/sass/svg/x.svg b/client/src/standalone/player/src/sass/svg/x.svg
new file mode 100644
index 00000000000..7d5875ca8bc
--- /dev/null
+++ b/client/src/standalone/player/src/sass/svg/x.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/src/assets/player/shared/bezels/bezels-plugin.ts b/client/src/standalone/player/src/shared/bezels/bezels-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/bezels/bezels-plugin.ts
rename to client/src/standalone/player/src/shared/bezels/bezels-plugin.ts
diff --git a/client/src/assets/player/shared/bezels/index.ts b/client/src/standalone/player/src/shared/bezels/index.ts
similarity index 100%
rename from client/src/assets/player/shared/bezels/index.ts
rename to client/src/standalone/player/src/shared/bezels/index.ts
diff --git a/client/src/assets/player/shared/bezels/pause-bezel.ts b/client/src/standalone/player/src/shared/bezels/pause-bezel.ts
similarity index 100%
rename from client/src/assets/player/shared/bezels/pause-bezel.ts
rename to client/src/standalone/player/src/shared/bezels/pause-bezel.ts
diff --git a/client/src/assets/player/shared/common/index.ts b/client/src/standalone/player/src/shared/common/index.ts
similarity index 100%
rename from client/src/assets/player/shared/common/index.ts
rename to client/src/standalone/player/src/shared/common/index.ts
diff --git a/client/src/assets/player/shared/common/utils.ts b/client/src/standalone/player/src/shared/common/utils.ts
similarity index 100%
rename from client/src/assets/player/shared/common/utils.ts
rename to client/src/standalone/player/src/shared/common/utils.ts
diff --git a/client/src/assets/player/shared/context-menu/context-menu-item.ts b/client/src/standalone/player/src/shared/context-menu/context-menu-item.ts
similarity index 100%
rename from client/src/assets/player/shared/context-menu/context-menu-item.ts
rename to client/src/standalone/player/src/shared/context-menu/context-menu-item.ts
diff --git a/client/src/assets/player/shared/context-menu/context-menu-plugin.ts b/client/src/standalone/player/src/shared/context-menu/context-menu-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/context-menu/context-menu-plugin.ts
rename to client/src/standalone/player/src/shared/context-menu/context-menu-plugin.ts
diff --git a/client/src/assets/player/shared/context-menu/context-menu.ts b/client/src/standalone/player/src/shared/context-menu/context-menu.ts
similarity index 100%
rename from client/src/assets/player/shared/context-menu/context-menu.ts
rename to client/src/standalone/player/src/shared/context-menu/context-menu.ts
diff --git a/client/src/assets/player/shared/context-menu/index.ts b/client/src/standalone/player/src/shared/context-menu/index.ts
similarity index 100%
rename from client/src/assets/player/shared/context-menu/index.ts
rename to client/src/standalone/player/src/shared/context-menu/index.ts
diff --git a/client/src/assets/player/shared/context-menu/util.ts b/client/src/standalone/player/src/shared/context-menu/util.ts
similarity index 100%
rename from client/src/assets/player/shared/context-menu/util.ts
rename to client/src/standalone/player/src/shared/context-menu/util.ts
diff --git a/client/src/assets/player/shared/control-bar/caption-toggle-button.ts b/client/src/standalone/player/src/shared/control-bar/caption-toggle-button.ts
similarity index 100%
rename from client/src/assets/player/shared/control-bar/caption-toggle-button.ts
rename to client/src/standalone/player/src/shared/control-bar/caption-toggle-button.ts
diff --git a/client/src/assets/player/shared/control-bar/chapters-plugin.ts b/client/src/standalone/player/src/shared/control-bar/chapters-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/control-bar/chapters-plugin.ts
rename to client/src/standalone/player/src/shared/control-bar/chapters-plugin.ts
diff --git a/client/src/assets/player/shared/control-bar/index.ts b/client/src/standalone/player/src/shared/control-bar/index.ts
similarity index 100%
rename from client/src/assets/player/shared/control-bar/index.ts
rename to client/src/standalone/player/src/shared/control-bar/index.ts
diff --git a/client/src/assets/player/shared/control-bar/next-previous-video-button.ts b/client/src/standalone/player/src/shared/control-bar/next-previous-video-button.ts
similarity index 100%
rename from client/src/assets/player/shared/control-bar/next-previous-video-button.ts
rename to client/src/standalone/player/src/shared/control-bar/next-previous-video-button.ts
diff --git a/client/src/assets/player/shared/control-bar/p2p-info-button.ts b/client/src/standalone/player/src/shared/control-bar/p2p-info-button.ts
similarity index 100%
rename from client/src/assets/player/shared/control-bar/p2p-info-button.ts
rename to client/src/standalone/player/src/shared/control-bar/p2p-info-button.ts
diff --git a/client/src/assets/player/shared/control-bar/peertube-link-button.ts b/client/src/standalone/player/src/shared/control-bar/peertube-link-button.ts
similarity index 100%
rename from client/src/assets/player/shared/control-bar/peertube-link-button.ts
rename to client/src/standalone/player/src/shared/control-bar/peertube-link-button.ts
diff --git a/client/src/assets/player/shared/control-bar/peertube-live-display.ts b/client/src/standalone/player/src/shared/control-bar/peertube-live-display.ts
similarity index 100%
rename from client/src/assets/player/shared/control-bar/peertube-live-display.ts
rename to client/src/standalone/player/src/shared/control-bar/peertube-live-display.ts
diff --git a/client/src/assets/player/shared/control-bar/progress-bar-marker-component.ts b/client/src/standalone/player/src/shared/control-bar/progress-bar-marker-component.ts
similarity index 100%
rename from client/src/assets/player/shared/control-bar/progress-bar-marker-component.ts
rename to client/src/standalone/player/src/shared/control-bar/progress-bar-marker-component.ts
diff --git a/client/src/assets/player/shared/control-bar/storyboard-plugin.ts b/client/src/standalone/player/src/shared/control-bar/storyboard-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/control-bar/storyboard-plugin.ts
rename to client/src/standalone/player/src/shared/control-bar/storyboard-plugin.ts
diff --git a/client/src/assets/player/shared/control-bar/theater-button.ts b/client/src/standalone/player/src/shared/control-bar/theater-button.ts
similarity index 100%
rename from client/src/assets/player/shared/control-bar/theater-button.ts
rename to client/src/standalone/player/src/shared/control-bar/theater-button.ts
diff --git a/client/src/assets/player/shared/control-bar/time-tooltip.ts b/client/src/standalone/player/src/shared/control-bar/time-tooltip.ts
similarity index 100%
rename from client/src/assets/player/shared/control-bar/time-tooltip.ts
rename to client/src/standalone/player/src/shared/control-bar/time-tooltip.ts
diff --git a/client/src/assets/player/shared/dock/index.ts b/client/src/standalone/player/src/shared/dock/index.ts
similarity index 100%
rename from client/src/assets/player/shared/dock/index.ts
rename to client/src/standalone/player/src/shared/dock/index.ts
diff --git a/client/src/assets/player/shared/dock/peertube-dock-component.ts b/client/src/standalone/player/src/shared/dock/peertube-dock-component.ts
similarity index 100%
rename from client/src/assets/player/shared/dock/peertube-dock-component.ts
rename to client/src/standalone/player/src/shared/dock/peertube-dock-component.ts
diff --git a/client/src/assets/player/shared/dock/peertube-dock-plugin.ts b/client/src/standalone/player/src/shared/dock/peertube-dock-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/dock/peertube-dock-plugin.ts
rename to client/src/standalone/player/src/shared/dock/peertube-dock-plugin.ts
diff --git a/client/src/assets/player/shared/hotkeys/index.ts b/client/src/standalone/player/src/shared/hotkeys/index.ts
similarity index 100%
rename from client/src/assets/player/shared/hotkeys/index.ts
rename to client/src/standalone/player/src/shared/hotkeys/index.ts
diff --git a/client/src/assets/player/shared/hotkeys/peertube-hotkeys-plugin.ts b/client/src/standalone/player/src/shared/hotkeys/peertube-hotkeys-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/hotkeys/peertube-hotkeys-plugin.ts
rename to client/src/standalone/player/src/shared/hotkeys/peertube-hotkeys-plugin.ts
diff --git a/client/src/assets/player/shared/metrics/index.ts b/client/src/standalone/player/src/shared/metrics/index.ts
similarity index 100%
rename from client/src/assets/player/shared/metrics/index.ts
rename to client/src/standalone/player/src/shared/metrics/index.ts
diff --git a/client/src/assets/player/shared/metrics/metrics-plugin.ts b/client/src/standalone/player/src/shared/metrics/metrics-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/metrics/metrics-plugin.ts
rename to client/src/standalone/player/src/shared/metrics/metrics-plugin.ts
diff --git a/client/src/assets/player/shared/mobile/index.ts b/client/src/standalone/player/src/shared/mobile/index.ts
similarity index 100%
rename from client/src/assets/player/shared/mobile/index.ts
rename to client/src/standalone/player/src/shared/mobile/index.ts
diff --git a/client/src/assets/player/shared/mobile/peertube-mobile-buttons.ts b/client/src/standalone/player/src/shared/mobile/peertube-mobile-buttons.ts
similarity index 100%
rename from client/src/assets/player/shared/mobile/peertube-mobile-buttons.ts
rename to client/src/standalone/player/src/shared/mobile/peertube-mobile-buttons.ts
diff --git a/client/src/assets/player/shared/mobile/peertube-mobile-plugin.ts b/client/src/standalone/player/src/shared/mobile/peertube-mobile-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/mobile/peertube-mobile-plugin.ts
rename to client/src/standalone/player/src/shared/mobile/peertube-mobile-plugin.ts
diff --git a/client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts b/client/src/standalone/player/src/shared/p2p-media-loader/hls-plugin.ts
similarity index 95%
rename from client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts
rename to client/src/standalone/player/src/shared/p2p-media-loader/hls-plugin.ts
index fd5fb2525ec..0bd34f8df65 100644
--- a/client/src/assets/player/shared/p2p-media-loader/hls-plugin.ts
+++ b/client/src/standalone/player/src/shared/p2p-media-loader/hls-plugin.ts
@@ -5,6 +5,10 @@ import { logger } from '@root-helpers/logger'
import Hlsjs, { ErrorData, Level, LevelSwitchingData, ManifestParsedData } from 'hls.js'
import videojs from 'video.js'
import { HLSPluginOptions, HlsjsConfigHandlerOptions, PeerTubeResolution, VideoJSTechHLS } from '../../types'
+import { HlsJsP2PEngine, HlsWithP2PInstance } from 'p2p-media-loader-hlsjs'
+import { omit } from '@peertube/peertube-core-utils'
+
+const HlsWithP2P = HlsJsP2PEngine.injectMixin(Hlsjs)
type ErrorCounts = {
[ type: string ]: number
@@ -14,8 +18,6 @@ type ErrorCounts = {
// Source handler registration
// ---------------------------------------------------------------------------
-type HookFn = (player: videojs.Player, hljs: Hlsjs) => void
-
let alreadyRegistered = false
const registerSourceHandler = function (vjs: typeof videojs) {
@@ -110,8 +112,6 @@ videojs.registerPlugin('hlsjs', HLSJSConfigHandler)
// ---------------------------------------------------------------------------
export class Html5Hlsjs {
- private static hooks: { [id: string]: HookFn[] } = {}
-
private readonly videoElement: HTMLVideoElement
private readonly errorCounts: ErrorCounts = {}
private readonly player: videojs.Player
@@ -121,7 +121,7 @@ export class Html5Hlsjs {
private maxNetworkErrorRecovery = 5
- private hls: Hlsjs
+ private hls: HlsWithP2PInstance
private hlsjsConfig: HLSPluginOptions = null
private _duration: number = null
@@ -410,10 +410,15 @@ export class Html5Hlsjs {
this.videoElement.addEventListener('play', this.handlers.play)
}
- const loader = this.hlsjsConfig.loaderBuilder()
- this.hls = new Hlsjs({ ...this.hlsjsConfig, loader })
+ this.hls = new HlsWithP2P({
+ ...omit(this.hlsjsConfig, [ 'p2pMediaLoaderOptions' ]),
- this.player.trigger('hlsjs-initialized', { hlsjs: this.hls, engine: loader.getEngine() })
+ p2p: {
+ core: this.hlsjsConfig.p2pMediaLoaderOptions
+ }
+ })
+
+ this.player.trigger('hlsjs-initialized', { hlsjs: this.hls })
this.hls.on(Hlsjs.Events.ERROR, (event, data) => this._onError(event, data))
this.hls.on(Hlsjs.Events.MANIFEST_PARSED, (event, data) => this._onMetaData(event, data))
@@ -462,17 +467,21 @@ export class Html5Hlsjs {
this.hlsjsConfig.autoStartLoad = true
this.player.autoplay('play')
- const loader = this.hlsjsConfig.loaderBuilder()
- this.hls = new Hlsjs({
- ...this.hlsjsConfig,
- loader,
+ this.hls = new HlsWithP2P({
+ ...omit(this.hlsjsConfig, [ 'p2pMediaLoaderOptions' ]),
+
+ p2p: {
+ core: this.hlsjsConfig.p2pMediaLoaderOptions
+ },
+
startPosition: this.duration() === Infinity
? undefined
: currentTime,
+
startLevel
})
- this.player.trigger('hlsjs-initialized', { hlsjs: this.hls, engine: loader.getEngine() })
+ this.player.trigger('hlsjs-initialized', { hlsjs: this.hls })
this.hls.on(Hlsjs.Events.ERROR, (event, data) => this._onError(event, data))
this.registerLevelEventSwitch()
diff --git a/client/src/assets/player/shared/p2p-media-loader/index.ts b/client/src/standalone/player/src/shared/p2p-media-loader/index.ts
similarity index 100%
rename from client/src/assets/player/shared/p2p-media-loader/index.ts
rename to client/src/standalone/player/src/shared/p2p-media-loader/index.ts
diff --git a/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts b/client/src/standalone/player/src/shared/p2p-media-loader/p2p-media-loader-plugin.ts
similarity index 74%
rename from client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts
rename to client/src/standalone/player/src/shared/p2p-media-loader/p2p-media-loader-plugin.ts
index abcbd226189..af52503f021 100644
--- a/client/src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts
+++ b/client/src/standalone/player/src/shared/p2p-media-loader/p2p-media-loader-plugin.ts
@@ -1,9 +1,9 @@
-import { Events, Segment } from '@peertube/p2p-media-loader-core'
-import { Engine, initHlsJsPlayer } from '@peertube/p2p-media-loader-hlsjs'
import { addQueryParams } from '@peertube/peertube-core-utils'
import { logger } from '@root-helpers/logger'
import debug from 'debug'
-import Hlsjs from 'hls.js'
+import { FragLoadedData, default as Hlsjs } from 'hls.js'
+import type { DownloadSource, SegmentErrorDetails, SegmentLoadDetails } from 'p2p-media-loader-core'
+import type { HlsWithP2PInstance } from 'p2p-media-loader-hlsjs'
import videojs from 'video.js'
import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo } from '../../types'
import { SettingsButton } from '../settings/settings-menu-button'
@@ -14,8 +14,7 @@ const Plugin = videojs.getPlugin('plugin')
class P2pMediaLoaderPlugin extends Plugin {
declare private readonly options: P2PMediaLoaderPluginOptions
- declare private hlsjs: Hlsjs
- declare private p2pEngine: Engine
+ declare private hlsjs: HlsWithP2PInstance
declare private statsP2PBytes: {
pendingDownload: number[]
pendingUpload: number[]
@@ -33,6 +32,9 @@ class P2pMediaLoaderPlugin extends Plugin {
declare private liveEnded: boolean
+ declare private connectedPeers: Set
+ declare private totalHTTPPeers: number
+
constructor (player: videojs.Player, options?: P2PMediaLoaderPluginOptions) {
super(player)
@@ -76,15 +78,13 @@ class P2pMediaLoaderPlugin extends Plugin {
}
{
- const onHLSJSInitialized = (_: any, { hlsjs, engine }: { hlsjs: Hlsjs, engine: Engine }) => {
- this.p2pEngine?.removeAllListeners()
- this.p2pEngine?.destroy()
+ const onHLSJSInitialized = (_: any, { hlsjs }: { hlsjs: HlsWithP2PInstance }) => {
+ this.hlsjs?.p2pEngine?.destroy()
clearInterval(this.networkInfoInterval)
this.hlsjs = hlsjs
- this.p2pEngine = engine
- debugLogger('hls.js initialized, initializing p2p-media-loader plugin', { hlsjs, engine })
+ debugLogger('hls.js initialized, initializing p2p-media-loader plugin', { hlsjs })
player.ready(() => this.initializePlugin())
}
@@ -116,8 +116,7 @@ class P2pMediaLoaderPlugin extends Plugin {
}
dispose () {
- this.p2pEngine?.removeAllListeners()
- this.p2pEngine?.destroy()
+ this.hlsjs?.p2pEngine?.destroy()
this.hlsjs?.destroy()
this.options.segmentValidator?.destroy()
@@ -152,15 +151,22 @@ class P2pMediaLoaderPlugin extends Plugin {
}
private initializePlugin () {
- initHlsJsPlayer(this.player, this.hlsjs)
+ this.hlsjs.p2pEngine.addEventListener('onSegmentError', (details: SegmentErrorDetails) => {
+ if (navigator.onLine === false || this.liveEnded || details.downloadSource !== 'http') return
+
+ const segment = details.segment
+ logger.clientError(`Segment ${segment.runtimeId} error.`, details)
- this.p2pEngine.on(Events.SegmentError, (segment: Segment, err) => {
- if (navigator.onLine === false || this.liveEnded) return
+ if (this.options.redundancyUrlManager) {
+ this.options.redundancyUrlManager.onSegmentError(segment.url)
+ }
+ })
- logger.clientError(`Segment ${segment.id} error.`, err)
+ this.hlsjs.p2pEngine.addEventListener('onSegmentLoaded', (details: SegmentLoadDetails) => {
+ if (details.downloadSource !== 'http') return
if (this.options.redundancyUrlManager) {
- this.options.redundancyUrlManager.removeBySegmentUrl(segment.requestUrl)
+ this.options.redundancyUrlManager.onSegmentSuccess(details.segmentUrl)
}
})
@@ -168,7 +174,8 @@ class P2pMediaLoaderPlugin extends Plugin {
? this.options.redundancyUrlManager.countBaseUrls()
: 0
- this.statsP2PBytes.peersWithWebSeed = 1 + redundancyUrlsCount
+ this.totalHTTPPeers = 1 + redundancyUrlsCount
+ this.statsP2PBytes.peersWithWebSeed = this.totalHTTPPeers
this.runStats()
@@ -200,30 +207,45 @@ class P2pMediaLoaderPlugin extends Plugin {
}
private runStats () {
- this.p2pEngine.on(Events.PieceBytesDownloaded, (method: string, _segment, bytes: number) => {
+ this.connectedPeers = new Set()
+
+ if (this.hlsjs.p2pEngine.getConfig().core.mainStream.isP2PDisabled) {
+ this.hlsjs.on(Hlsjs.Events.FRAG_LOADED, (e, data: FragLoadedData) => {
+ const bytes = data.frag.stats.loaded
+ console.log(bytes)
+
+ this.statsHTTPBytes.pendingDownload.push(bytes)
+ this.statsHTTPBytes.totalDownload += bytes
+ })
+ }
+
+ this.hlsjs.p2pEngine.addEventListener('onChunkDownloaded', (bytes: number, method: DownloadSource) => {
const elem = method === 'p2p' ? this.statsP2PBytes : this.statsHTTPBytes
elem.pendingDownload.push(bytes)
elem.totalDownload += bytes
})
- this.p2pEngine.on(Events.PieceBytesUploaded, (method: string, _segment, bytes: number) => {
- if (method !== 'p2p') {
- logger.error(`Received upload from unknown method ${method}`)
- return
- }
-
+ this.hlsjs.p2pEngine.addEventListener('onChunkUploaded', (bytes: number) => {
this.statsP2PBytes.pendingUpload.push(bytes)
this.statsP2PBytes.totalUpload += bytes
})
- this.p2pEngine.on(Events.PeerConnect, () => {
- this.statsP2PBytes.peersWithWebSeed++
- this.statsP2PBytes.peersP2POnly++
+ this.hlsjs.p2pEngine.addEventListener('onPeerConnect', peer => {
+ if (peer.streamType !== 'main') return
+
+ this.connectedPeers.add(peer.peerId)
+ this.statsP2PBytes.peersP2POnly = this.connectedPeers.size
+
+ this.statsP2PBytes.peersWithWebSeed = this.totalHTTPPeers + this.statsP2PBytes.peersP2POnly
})
- this.p2pEngine.on(Events.PeerClose, () => {
- this.statsP2PBytes.peersWithWebSeed--
- this.statsP2PBytes.peersP2POnly--
+ this.hlsjs.p2pEngine.addEventListener('onPeerClose', peer => {
+ if (peer.streamType !== 'main') return
+
+ this.connectedPeers.delete(peer.peerId)
+ this.statsP2PBytes.peersP2POnly = this.connectedPeers.size
+
+ this.statsP2PBytes.peersWithWebSeed = this.totalHTTPPeers + this.statsP2PBytes.peersP2POnly
})
this.networkInfoInterval = setInterval(() => {
diff --git a/client/src/assets/player/shared/p2p-media-loader/redundancy-url-manager.ts b/client/src/standalone/player/src/shared/p2p-media-loader/redundancy-url-manager.ts
similarity index 67%
rename from client/src/assets/player/shared/p2p-media-loader/redundancy-url-manager.ts
rename to client/src/standalone/player/src/shared/p2p-media-loader/redundancy-url-manager.ts
index ab051ca4450..ec7a219b7fc 100644
--- a/client/src/assets/player/shared/p2p-media-loader/redundancy-url-manager.ts
+++ b/client/src/standalone/player/src/shared/p2p-media-loader/redundancy-url-manager.ts
@@ -1,22 +1,32 @@
import { logger } from '@root-helpers/logger'
class RedundancyUrlManager {
+ private map = new Map()
constructor (private baseUrls: string[] = []) {
// empty
}
- removeBySegmentUrl (segmentUrl: string) {
- const baseUrl = getBaseUrl(segmentUrl)
+ onSegmentError (segmentUrl: string) {
+ if (!this.map.has(segmentUrl)) return
+
+ const customSegmentUrl = this.map.get(segmentUrl)
+ this.map.delete(segmentUrl)
+
+ const baseUrl = getBaseUrl(customSegmentUrl)
const oldLength = baseUrl.length
this.baseUrls = this.baseUrls.filter(u => u !== baseUrl && u !== baseUrl + '/')
if (oldLength !== this.baseUrls.length) {
- logger.info(`Removed redundancy of segment URL ${segmentUrl}.`)
+ logger.info(`Removed redundancy of segment URL ${customSegmentUrl}.`)
}
}
+ onSegmentSuccess (segmentUrl: string) {
+ this.map.delete(segmentUrl)
+ }
+
buildUrl (url: string) {
const max = this.baseUrls.length + 1
const i = this.getRandomInt(max)
@@ -26,7 +36,11 @@ class RedundancyUrlManager {
const newBaseUrl = this.baseUrls[i]
const slashPart = newBaseUrl.endsWith('/') ? '' : '/'
- return newBaseUrl + slashPart + getFilename(url)
+ const newUrl = newBaseUrl + slashPart + getFilename(url)
+
+ this.map.set(url, newUrl)
+
+ return newUrl
}
countBaseUrls () {
diff --git a/client/src/assets/player/shared/p2p-media-loader/segment-url-builder.ts b/client/src/standalone/player/src/shared/p2p-media-loader/segment-url-builder.ts
similarity index 80%
rename from client/src/assets/player/shared/p2p-media-loader/segment-url-builder.ts
rename to client/src/standalone/player/src/shared/p2p-media-loader/segment-url-builder.ts
index 8875e5353c1..9cd1d979c11 100644
--- a/client/src/assets/player/shared/p2p-media-loader/segment-url-builder.ts
+++ b/client/src/standalone/player/src/shared/p2p-media-loader/segment-url-builder.ts
@@ -1,8 +1,9 @@
-import { Segment } from '@peertube/p2p-media-loader-core'
+import type { Segment } from 'p2p-media-loader-core'
import { RedundancyUrlManager } from './redundancy-url-manager'
export function segmentUrlBuilderFactory (redundancyUrlManager: RedundancyUrlManager | null) {
return function segmentBuilder (segment: Segment) {
+ console.log(segment)
if (!redundancyUrlManager) return segment.url
return redundancyUrlManager.buildUrl(segment.url)
diff --git a/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts b/client/src/standalone/player/src/shared/p2p-media-loader/segment-validator.ts
similarity index 76%
rename from client/src/assets/player/shared/p2p-media-loader/segment-validator.ts
rename to client/src/standalone/player/src/shared/p2p-media-loader/segment-validator.ts
index e5f6631171c..d88ba5ebc48 100644
--- a/client/src/assets/player/shared/p2p-media-loader/segment-validator.ts
+++ b/client/src/standalone/player/src/shared/p2p-media-loader/segment-validator.ts
@@ -1,9 +1,9 @@
-import { Segment } from '@peertube/p2p-media-loader-core'
+import type { ByteRange } from 'p2p-media-loader-core'
+import { removeQueryParams } from '@peertube/peertube-core-utils'
import { logger } from '@root-helpers/logger'
import { wait } from '@root-helpers/utils'
-import { removeQueryParams } from '@peertube/peertube-core-utils'
-import { isSameOrigin } from '../common'
import debug from 'debug'
+import { isSameOrigin } from '../common'
const debugLogger = debug('peertube:player:segment-validator')
@@ -12,9 +12,6 @@ type SegmentsJSON = { [filename: string]: string | { [byterange: string]: string
const maxRetries = 10
export class SegmentValidator {
-
- private readonly bytesRangeRegex = /bytes=(\d+)-(\d+)/
-
private destroyed = false
private segmentJSONPromise: Promise
@@ -29,17 +26,18 @@ export class SegmentValidator {
}) {
}
- async validate (segment: Segment, _method: string, _peerId: string, retry = 1) {
- if (this.destroyed) return
+ async validate (url: string, byteRange: ByteRange | undefined, data: ArrayBuffer, retry = 1): Promise {
+ if (this.destroyed) return false
this.loadSha256SegmentsPromiseIfNeeded()
- const filename = removeQueryParams(segment.url).split('/').pop()
+ const filename = removeQueryParams(url).split('/').pop()
const segmentValue = (await this.segmentJSONPromise)[filename]
if (!segmentValue && retry > maxRetries) {
- throw new Error(`Unknown segment name ${filename} in segment validator`)
+ logger.clientError(`Unknown segment name ${filename} in segment validator`)
+ return false
}
if (!segmentValue) {
@@ -49,9 +47,7 @@ export class SegmentValidator {
this.loadSha256SegmentsPromise()
- await this.validate(segment, _method, _peerId, retry + 1)
-
- return
+ return this.validate(url, byteRange, data, retry + 1)
}
let hashShouldBe: string
@@ -60,24 +56,25 @@ export class SegmentValidator {
if (typeof segmentValue === 'string') {
hashShouldBe = segmentValue
} else {
- const captured = this.bytesRangeRegex.exec(segment.range)
- range = captured[1] + '-' + captured[2]
+ range = byteRange.start + '-' + byteRange.end
hashShouldBe = segmentValue[range]
}
if (hashShouldBe === undefined) {
- throw new Error(`Unknown segment name ${filename}/${range} in segment validator`)
+ logger.clientError(`Unknown segment name ${filename}/${range} in segment validator`)
+ return false
}
- debugLogger(`Validating ${filename}` + (segment.range ? ` range ${segment.range}` : ''))
+ debugLogger(`Validating ${filename}` + (range ? ` range ${range}` : ''))
- const calculatedSha = await this.sha256Hex(segment.data)
+ const calculatedSha = await this.sha256Hex(data)
if (calculatedSha !== hashShouldBe) {
- throw new Error(
- `Hashes does not correspond for segment ${filename}/${range}` +
- `(expected: ${hashShouldBe} instead of ${calculatedSha})`
+ logger.clientError(
+ `Hashes does not correspond for segment ${filename}/${range} (expected: ${hashShouldBe} instead of ${calculatedSha})`
)
+
+ return true
}
}
@@ -106,7 +103,7 @@ export class SegmentValidator {
return fetch(this.options.segmentsSha256Url, { headers })
.then(res => res.json() as Promise)
.catch(err => {
- logger.error('Cannot get sha256 segments', err)
+ logger.clientError('Cannot get sha256 segments', err)
return {}
})
}
diff --git a/client/src/assets/player/shared/peertube/index.ts b/client/src/standalone/player/src/shared/peertube/index.ts
similarity index 100%
rename from client/src/assets/player/shared/peertube/index.ts
rename to client/src/standalone/player/src/shared/peertube/index.ts
diff --git a/client/src/assets/player/shared/peertube/peertube-plugin.ts b/client/src/standalone/player/src/shared/peertube/peertube-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/peertube/peertube-plugin.ts
rename to client/src/standalone/player/src/shared/peertube/peertube-plugin.ts
diff --git a/client/src/assets/player/shared/player-options-builder/control-bar-options-builder.ts b/client/src/standalone/player/src/shared/player-options-builder/control-bar-options-builder.ts
similarity index 100%
rename from client/src/assets/player/shared/player-options-builder/control-bar-options-builder.ts
rename to client/src/standalone/player/src/shared/player-options-builder/control-bar-options-builder.ts
diff --git a/client/src/assets/player/shared/player-options-builder/hls-options-builder.ts b/client/src/standalone/player/src/shared/player-options-builder/hls-options-builder.ts
similarity index 65%
rename from client/src/assets/player/shared/player-options-builder/hls-options-builder.ts
rename to client/src/standalone/player/src/shared/player-options-builder/hls-options-builder.ts
index db33c06c3dc..7dfcb69ba04 100644
--- a/client/src/assets/player/shared/player-options-builder/hls-options-builder.ts
+++ b/client/src/standalone/player/src/shared/player-options-builder/hls-options-builder.ts
@@ -1,13 +1,11 @@
-import { HybridLoaderSettings } from '@peertube/p2p-media-loader-core'
-import { Engine, HlsJsEngineSettings } from '@peertube/p2p-media-loader-hlsjs'
import { getResolutionAndFPSLabel, getResolutionLabel } from '@peertube/peertube-core-utils'
import { LiveVideoLatencyMode } from '@peertube/peertube-models'
import { logger } from '@root-helpers/logger'
-import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
+import debug from 'debug'
import { Level } from 'hls.js'
+import type { ByteRange, CoreConfig, StreamConfig } from 'p2p-media-loader-core'
import { getAverageBandwidthInStore } from '../../peertube-player-local-storage'
import {
- HLSLoaderClass,
HLSPluginOptions,
P2PMediaLoaderPluginOptions,
PeerTubePlayerConstructorOptions,
@@ -15,9 +13,8 @@ import {
} from '../../types'
import { getRtcConfig, isSameOrigin } from '../common'
import { RedundancyUrlManager } from '../p2p-media-loader/redundancy-url-manager'
-import { segmentUrlBuilderFactory } from '../p2p-media-loader/segment-url-builder'
import { SegmentValidator } from '../p2p-media-loader/segment-validator'
-import debug from 'debug'
+import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
const debugLogger = debug('peertube:player:hls')
@@ -58,7 +55,6 @@ export class HLSOptionsBuilder {
'filter:internal.player.p2p-media-loader.options.result',
this.getP2PMediaLoaderOptions({ redundancyUrlManager, segmentValidator })
)
- const loaderBuilder = () => new Engine(p2pMediaLoaderConfig).createLoaderClass() as unknown as HLSLoaderClass
const p2pMediaLoader: P2PMediaLoaderPluginOptions = {
requiresUserAuth: this.options.requiresUserAuth,
@@ -73,7 +69,7 @@ export class HLSOptionsBuilder {
}
const hlsjs = {
- hlsjsConfig: this.getHLSJSOptions(loaderBuilder),
+ hlsjsConfig: this.getHLSJSOptions(p2pMediaLoaderConfig),
levelLabelHandler: (level: Level, player: videojs.VideoJsPlayer) => {
const resolution = Math.min(level.height || 0, level.width || 0)
@@ -99,65 +95,81 @@ export class HLSOptionsBuilder {
private getP2PMediaLoaderOptions (options: {
redundancyUrlManager: RedundancyUrlManager | null
segmentValidator: SegmentValidator | null
- }): HlsJsEngineSettings {
+ }) {
const { redundancyUrlManager, segmentValidator } = options
- let consumeOnly = false
+ let isP2PUploadDisabled = false
if (
(navigator as any)?.connection?.type === 'cellular' ||
peertubeLocalStorage.getItem('peertube-videojs-p2p-consume-only') === 'true' // Use for E2E testing
) {
logger.info('We are on a cellular connection: disabling seeding.')
- consumeOnly = true
+ isP2PUploadDisabled = true
}
- const trackerAnnounce = this.options.hls.trackerAnnounce
+ const announceTrackers = this.options.hls.trackerAnnounce
.filter(t => t.startsWith('ws'))
const specificLiveOrVODOptions = this.options.isLive
? this.getP2PMediaLoaderLiveOptions()
: this.getP2PMediaLoaderVODOptions()
- return {
- loader: {
- trackerAnnounce,
- rtcConfig: getRtcConfig(this.options.stunServers),
+ // TODO: remove validateHTTPSegment typing when p2p-media-loader-core is updated
+ const loaderOptions: Partial & { validateHTTPSegment: any } = {
+ announceTrackers,
+ rtcConfig: getRtcConfig(this.options.stunServers),
- simultaneousHttpDownloads: 1,
- httpFailedSegmentTimeout: 1000,
+ httpRequestSetup: (segmentUrlArg, segmentByteRange, requestAbortSignal, requestByteRange) => {
+ const { requiresUserAuth, requiresPassword } = this.options
- xhrSetup: (xhr, url) => {
- const { requiresUserAuth, requiresPassword } = this.options
+ const segmentUrl = redundancyUrlManager
+ ? redundancyUrlManager.buildUrl(segmentUrlArg)
+ : segmentUrlArg
- if (!(requiresUserAuth || requiresPassword)) return
+ const headers = new Headers()
- if (!isSameOrigin(this.options.serverUrl, url)) return
+ if (requestByteRange) {
+ headers.set('Range', `bytes=${requestByteRange.start}-${requestByteRange.end ?? ''}`)
+ }
- if (requiresPassword) xhr.setRequestHeader('x-peertube-video-password', this.options.videoPassword())
- else xhr.setRequestHeader('Authorization', this.options.authorizationHeader())
- },
+ if (isSameOrigin(this.options.serverUrl, segmentUrl)) {
+ if (requiresPassword) {
+ headers.set('x-peertube-video-password', this.options.videoPassword())
+ } else if (requiresUserAuth) {
+ headers.set('Authorization', this.options.authorizationHeader())
+ }
+ }
- segmentValidator: segmentValidator
- ? segmentValidator.validate.bind(segmentValidator)
- : null,
+ return Promise.resolve(
+ new Request(segmentUrl, {
+ headers,
+ signal: requestAbortSignal
+ })
+ )
+ },
- segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager),
+ validateP2PSegment: segmentValidator
+ ? segmentValidator.validate.bind(segmentValidator)
+ : null,
- useP2P: this.options.p2pEnabled,
- consumeOnly,
+ validateHTTPSegment: segmentValidator
+ ? segmentValidator.validate.bind(segmentValidator)
+ : null,
- ...specificLiveOrVODOptions
- },
- segments: {
- swarmId: this.options.hls.playlistUrl,
- forwardSegmentCount: specificLiveOrVODOptions.p2pDownloadMaxPriority ?? 20
- }
+ isP2PDisabled: !this.options.p2pEnabled,
+ isP2PUploadDisabled,
+
+ swarmId: this.options.hls.playlistUrl,
+
+ ...specificLiveOrVODOptions
}
+
+ return { loader: loaderOptions }
}
- private getP2PMediaLoaderLiveOptions (): Partial {
+ private getP2PMediaLoaderLiveOptions (): Partial {
const base = {
- requiredSegmentsPriority: 1
+ highDemandTimeWindow: 4
}
const latencyMode = this.options.liveOptions.latencyMode
@@ -167,8 +179,7 @@ export class HLSOptionsBuilder {
return {
...base,
- useP2P: false,
- requiredSegmentsPriority: 10
+ isP2PDisabled: true
}
case LiveVideoLatencyMode.HIGH_LATENCY:
@@ -179,34 +190,39 @@ export class HLSOptionsBuilder {
}
}
- private getP2PMediaLoaderVODOptions (): Partial {
+ private getP2PMediaLoaderVODOptions (): Partial {
return {
- requiredSegmentsPriority: 3,
- skipSegmentBuilderPriority: 1,
-
- cachedSegmentExpiration: 86400000,
- cachedSegmentsCount: 100,
-
- httpDownloadMaxPriority: 9,
- httpDownloadProbability: 0.06,
- httpDownloadProbabilitySkipIfNoPeers: true,
+ highDemandTimeWindow: 15,
- p2pDownloadMaxPriority: 50
+ segmentMemoryStorageLimit: 1024
}
}
// ---------------------------------------------------------------------------
- private getHLSJSOptions (loaderBuilder: () => HLSLoaderClass): HLSPluginOptions {
+ private getHLSJSOptions (p2pMediaLoaderConfig: { loader: CoreConfig }): HLSPluginOptions {
const specificLiveOrVODOptions = this.options.isLive
? this.getHLSLiveOptions()
: this.getHLSVODOptions()
- const base = {
+ const base: HLSPluginOptions = {
capLevelToPlayerSize: true,
autoStartLoad: false,
- loaderBuilder,
+ p2pMediaLoaderOptions: p2pMediaLoaderConfig.loader,
+
+ // p2p-media-loader uses hls.js loader to fetch m3u8 playlists
+ xhrSetup: (xhr, url) => {
+ const { requiresUserAuth, requiresPassword } = this.options
+
+ if (isSameOrigin(this.options.serverUrl, url)) {
+ if (requiresPassword) {
+ xhr.setRequestHeader('x-peertube-video-password', this.options.videoPassword())
+ } else if (requiresUserAuth) {
+ xhr.setRequestHeader('Authorization', this.options.authorizationHeader())
+ }
+ }
+ },
...specificLiveOrVODOptions
}
diff --git a/client/src/assets/player/shared/player-options-builder/index.ts b/client/src/standalone/player/src/shared/player-options-builder/index.ts
similarity index 100%
rename from client/src/assets/player/shared/player-options-builder/index.ts
rename to client/src/standalone/player/src/shared/player-options-builder/index.ts
diff --git a/client/src/assets/player/shared/player-options-builder/web-video-options-builder.ts b/client/src/standalone/player/src/shared/player-options-builder/web-video-options-builder.ts
similarity index 100%
rename from client/src/assets/player/shared/player-options-builder/web-video-options-builder.ts
rename to client/src/standalone/player/src/shared/player-options-builder/web-video-options-builder.ts
diff --git a/client/src/assets/player/shared/playlist/index.ts b/client/src/standalone/player/src/shared/playlist/index.ts
similarity index 100%
rename from client/src/assets/player/shared/playlist/index.ts
rename to client/src/standalone/player/src/shared/playlist/index.ts
diff --git a/client/src/assets/player/shared/playlist/playlist-button.ts b/client/src/standalone/player/src/shared/playlist/playlist-button.ts
similarity index 100%
rename from client/src/assets/player/shared/playlist/playlist-button.ts
rename to client/src/standalone/player/src/shared/playlist/playlist-button.ts
diff --git a/client/src/assets/player/shared/playlist/playlist-menu-item.ts b/client/src/standalone/player/src/shared/playlist/playlist-menu-item.ts
similarity index 100%
rename from client/src/assets/player/shared/playlist/playlist-menu-item.ts
rename to client/src/standalone/player/src/shared/playlist/playlist-menu-item.ts
diff --git a/client/src/assets/player/shared/playlist/playlist-menu.ts b/client/src/standalone/player/src/shared/playlist/playlist-menu.ts
similarity index 100%
rename from client/src/assets/player/shared/playlist/playlist-menu.ts
rename to client/src/standalone/player/src/shared/playlist/playlist-menu.ts
diff --git a/client/src/assets/player/shared/playlist/playlist-plugin.ts b/client/src/standalone/player/src/shared/playlist/playlist-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/playlist/playlist-plugin.ts
rename to client/src/standalone/player/src/shared/playlist/playlist-plugin.ts
diff --git a/client/src/assets/player/shared/resolutions/index.ts b/client/src/standalone/player/src/shared/resolutions/index.ts
similarity index 100%
rename from client/src/assets/player/shared/resolutions/index.ts
rename to client/src/standalone/player/src/shared/resolutions/index.ts
diff --git a/client/src/assets/player/shared/resolutions/peertube-resolutions-plugin.ts b/client/src/standalone/player/src/shared/resolutions/peertube-resolutions-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/resolutions/peertube-resolutions-plugin.ts
rename to client/src/standalone/player/src/shared/resolutions/peertube-resolutions-plugin.ts
diff --git a/client/src/assets/player/shared/settings/index.ts b/client/src/standalone/player/src/shared/settings/index.ts
similarity index 100%
rename from client/src/assets/player/shared/settings/index.ts
rename to client/src/standalone/player/src/shared/settings/index.ts
diff --git a/client/src/assets/player/shared/settings/menu-focus-fixed.ts b/client/src/standalone/player/src/shared/settings/menu-focus-fixed.ts
similarity index 100%
rename from client/src/assets/player/shared/settings/menu-focus-fixed.ts
rename to client/src/standalone/player/src/shared/settings/menu-focus-fixed.ts
diff --git a/client/src/assets/player/shared/settings/resolution-menu-button.ts b/client/src/standalone/player/src/shared/settings/resolution-menu-button.ts
similarity index 100%
rename from client/src/assets/player/shared/settings/resolution-menu-button.ts
rename to client/src/standalone/player/src/shared/settings/resolution-menu-button.ts
diff --git a/client/src/assets/player/shared/settings/resolution-menu-item.ts b/client/src/standalone/player/src/shared/settings/resolution-menu-item.ts
similarity index 100%
rename from client/src/assets/player/shared/settings/resolution-menu-item.ts
rename to client/src/standalone/player/src/shared/settings/resolution-menu-item.ts
diff --git a/client/src/assets/player/shared/settings/settings-dialog.ts b/client/src/standalone/player/src/shared/settings/settings-dialog.ts
similarity index 100%
rename from client/src/assets/player/shared/settings/settings-dialog.ts
rename to client/src/standalone/player/src/shared/settings/settings-dialog.ts
diff --git a/client/src/assets/player/shared/settings/settings-menu-button.ts b/client/src/standalone/player/src/shared/settings/settings-menu-button.ts
similarity index 100%
rename from client/src/assets/player/shared/settings/settings-menu-button.ts
rename to client/src/standalone/player/src/shared/settings/settings-menu-button.ts
diff --git a/client/src/assets/player/shared/settings/settings-menu-item.ts b/client/src/standalone/player/src/shared/settings/settings-menu-item.ts
similarity index 100%
rename from client/src/assets/player/shared/settings/settings-menu-item.ts
rename to client/src/standalone/player/src/shared/settings/settings-menu-item.ts
diff --git a/client/src/assets/player/shared/settings/settings-panel-child.ts b/client/src/standalone/player/src/shared/settings/settings-panel-child.ts
similarity index 100%
rename from client/src/assets/player/shared/settings/settings-panel-child.ts
rename to client/src/standalone/player/src/shared/settings/settings-panel-child.ts
diff --git a/client/src/assets/player/shared/settings/settings-panel.ts b/client/src/standalone/player/src/shared/settings/settings-panel.ts
similarity index 100%
rename from client/src/assets/player/shared/settings/settings-panel.ts
rename to client/src/standalone/player/src/shared/settings/settings-panel.ts
diff --git a/client/src/assets/player/shared/stats/index.ts b/client/src/standalone/player/src/shared/stats/index.ts
similarity index 100%
rename from client/src/assets/player/shared/stats/index.ts
rename to client/src/standalone/player/src/shared/stats/index.ts
diff --git a/client/src/assets/player/shared/stats/stats-card.ts b/client/src/standalone/player/src/shared/stats/stats-card.ts
similarity index 99%
rename from client/src/assets/player/shared/stats/stats-card.ts
rename to client/src/standalone/player/src/shared/stats/stats-card.ts
index de25cae35cf..01971c7d0f9 100644
--- a/client/src/assets/player/shared/stats/stats-card.ts
+++ b/client/src/standalone/player/src/shared/stats/stats-card.ts
@@ -138,6 +138,8 @@ class StatsCard extends Component {
this.containerEl.style.display = 'block'
this.updateInterval = setInterval(async () => {
+ if (!this.mode) return
+
try {
const options = this.mode === 'p2p-media-loader'
? this.buildHLSOptions()
diff --git a/client/src/assets/player/shared/stats/stats-plugin.ts b/client/src/standalone/player/src/shared/stats/stats-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/stats/stats-plugin.ts
rename to client/src/standalone/player/src/shared/stats/stats-plugin.ts
diff --git a/client/src/assets/player/shared/upnext/end-card.ts b/client/src/standalone/player/src/shared/upnext/end-card.ts
similarity index 100%
rename from client/src/assets/player/shared/upnext/end-card.ts
rename to client/src/standalone/player/src/shared/upnext/end-card.ts
diff --git a/client/src/assets/player/shared/upnext/index.ts b/client/src/standalone/player/src/shared/upnext/index.ts
similarity index 100%
rename from client/src/assets/player/shared/upnext/index.ts
rename to client/src/standalone/player/src/shared/upnext/index.ts
diff --git a/client/src/assets/player/shared/upnext/upnext-plugin.ts b/client/src/standalone/player/src/shared/upnext/upnext-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/upnext/upnext-plugin.ts
rename to client/src/standalone/player/src/shared/upnext/upnext-plugin.ts
diff --git a/client/src/assets/player/shared/web-video/web-video-plugin.ts b/client/src/standalone/player/src/shared/web-video/web-video-plugin.ts
similarity index 100%
rename from client/src/assets/player/shared/web-video/web-video-plugin.ts
rename to client/src/standalone/player/src/shared/web-video/web-video-plugin.ts
diff --git a/client/src/assets/player/types/index.ts b/client/src/standalone/player/src/types/index.ts
similarity index 100%
rename from client/src/assets/player/types/index.ts
rename to client/src/standalone/player/src/types/index.ts
diff --git a/client/src/assets/player/types/peertube-player-options.ts b/client/src/standalone/player/src/types/peertube-player-options.ts
similarity index 100%
rename from client/src/assets/player/types/peertube-player-options.ts
rename to client/src/standalone/player/src/types/peertube-player-options.ts
diff --git a/client/src/assets/player/types/peertube-videojs-typings.ts b/client/src/standalone/player/src/types/peertube-videojs-typings.ts
similarity index 96%
rename from client/src/assets/player/types/peertube-videojs-typings.ts
rename to client/src/standalone/player/src/types/peertube-videojs-typings.ts
index 671d2f56951..b78038e271a 100644
--- a/client/src/assets/player/types/peertube-videojs-typings.ts
+++ b/client/src/standalone/player/src/types/peertube-videojs-typings.ts
@@ -1,6 +1,7 @@
-import { Engine } from '@peertube/p2p-media-loader-hlsjs'
import { VideoChapter, VideoFile, VideoPlaylist, VideoPlaylistElement } from '@peertube/peertube-models'
import type { HlsConfig, Level, Loader, LoaderContext } from 'hls.js'
+import type { CoreConfig } from 'p2p-media-loader-core'
+import type { HlsJsP2PEngine } from 'p2p-media-loader-hlsjs'
import videojs from 'video.js'
import { BezelsPlugin } from '../shared/bezels/bezels-plugin'
import { ContextMenuPlugin } from '../shared/context-menu'
@@ -215,9 +216,9 @@ export type WebVideoPluginOptions = {
export type HLSLoaderClass = {
new (confg: HlsConfig): Loader
- getEngine(): Engine
+ getEngine(): HlsJsP2PEngine
}
-export type HLSPluginOptions = Partial HLSLoaderClass }>
+export type HLSPluginOptions = Partial
export type P2PMediaLoaderPluginOptions = {
redundancyUrlManager: RedundancyUrlManager | null
@@ -233,7 +234,7 @@ export type P2PMediaLoaderPluginOptions = {
}
export type P2PMediaLoader = {
- getEngine(): Engine
+ getEngine(): HlsJsP2PEngine
destroy: () => void
}
diff --git a/client/src/standalone/player/tsconfig.json b/client/src/standalone/player/tsconfig.json
new file mode 100644
index 00000000000..c2187c8c04a
--- /dev/null
+++ b/client/src/standalone/player/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "extends": "../../../tsconfig.json",
+ "include": [
+ "./index.ts"
+ ]
+}
diff --git a/client/src/standalone/player/vite.config.mjs b/client/src/standalone/player/vite.config.mjs
new file mode 100644
index 00000000000..1e9a2ae6d1c
--- /dev/null
+++ b/client/src/standalone/player/vite.config.mjs
@@ -0,0 +1,47 @@
+import { nodePolyfills } from 'vite-plugin-node-polyfills'
+import { dirname, resolve } from 'path'
+import { fileURLToPath } from 'url'
+import { defineConfig } from 'vite'
+import checker from 'vite-plugin-checker'
+
+import { getCSSConfig, getAliasConfig } from '../build-tools/vite-utils.js'
+
+const __dirname = dirname(fileURLToPath(import.meta.url));
+const root = resolve(__dirname, '../../../')
+
+export default defineConfig(() => {
+ return {
+ build: {
+ outDir: resolve(__dirname, 'build'),
+ emptyOutDir: false,
+ minify: false,
+ lib: {
+ formats: [ 'es' ],
+ entry: resolve(__dirname, './src/index.ts'),
+ name: 'PeerTubePlayer',
+ fileName: 'peertube-player',
+ cssFilename: 'peertube-player.css'
+ }
+ },
+
+ css: getCSSConfig(root),
+
+ resolve: {
+ alias: getAliasConfig(root),
+
+ conditions: [
+ 'p2pml:core-as-bundle', 'defaultClientConditions'
+ ]
+ },
+
+ plugins: [
+ checker({
+ typescript: {
+ tsconfigPath: resolve(__dirname, 'tsconfig.json')
+ }
+ }),
+
+ nodePolyfills()
+ ]
+ }
+})
diff --git a/client/src/standalone/videos/embed.scss b/client/src/standalone/videos/embed.scss
index 44082e4a031..8f25b750124 100644
--- a/client/src/standalone/videos/embed.scss
+++ b/client/src/standalone/videos/embed.scss
@@ -1,11 +1,7 @@
@use '_variables' as *;
@use '_mixins' as *;
@use '_css-variables' as *;
-@use 'video.js/dist/video-js';
-
-$assets-path: '../../assets/';
-
-@use '../../sass/player/index';
+@use '../player/build/peertube-player';
[hidden] {
display: none !important;
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index dbb9478fe5b..74af84059c4 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -1,8 +1,3 @@
-import './embed.scss'
-import '../../assets/player/shared/dock/peertube-dock-component'
-import '../../assets/player/shared/dock/peertube-dock-plugin'
-import { PeerTubeServerError } from 'src/types'
-import videojs from 'video.js'
import {
HTMLServerConfig,
ResultList,
@@ -12,10 +7,13 @@ import {
VideoPlaylistElement,
VideoState
} from '@peertube/peertube-models'
-import { PeerTubePlayer } from '../../assets/player/peertube-player'
-import { TranslationsManager } from '../../assets/player/translations-manager'
+import type { PeerTubePlayer } from '@peertube/player'
+import { TranslationsManager } from '@root-helpers/translations-manager'
+import { PeerTubeServerError } from 'src/types'
+import type videojs from 'video.js'
import { getParamString, logger, videoRequiresFileToken } from '../../root-helpers'
import { PeerTubeEmbedApi } from './embed-api'
+import './embed.scss'
import {
AuthHTTP,
LiveManager,
@@ -37,6 +35,7 @@ export class PeerTubeEmbed {
private translationsPromise: Promise<{ [id: string]: string }>
private PeerTubePlayerManagerModulePromise: Promise
+ private videojs: typeof videojs
private readonly http: AuthHTTP
private readonly videoFetcher: VideoFetcher
@@ -94,7 +93,7 @@ export class PeerTubeEmbed {
async init () {
this.translationsPromise = TranslationsManager.getServerTranslations(getBackendUrl(), navigator.language)
- this.PeerTubePlayerManagerModulePromise = import('../../assets/player/peertube-player')
+ this.PeerTubePlayerManagerModulePromise = import('@peertube/player')
// Issue when we parsed config from HTML, fallback to API
if (!this.config) {
@@ -334,7 +333,11 @@ export class PeerTubeEmbed {
}
}
- this.peertubePlugin.getPluginsManager().runHook('action:embed.player.loaded', undefined, { player: this.player, videojs, video })
+ this.peertubePlugin.getPluginsManager().runHook(
+ 'action:embed.player.loaded',
+ undefined,
+ { player: this.player, videojs: this.videojs, video }
+ )
}
private buildCSS () {
@@ -430,11 +433,13 @@ export class PeerTubeEmbed {
this.playerHTML.setInitVideoEl(playerElement)
this.playerHTML.addInitVideoElToDOM()
- const [ { PeerTubePlayer } ] = await Promise.all([
+ const [ { PeerTubePlayer, videojs } ] = await Promise.all([
this.PeerTubePlayerManagerModulePromise,
this.peertubePlugin.loadPlugins(this.config, await this.translationsPromise)
])
+ this.videojs = videojs
+
const constructorOptions = this.playerOptionsBuilder.getPlayerConstructorOptions({
serverConfig: this.config,
authorizationHeader: () => this.http.getHeaderTokenValue()
diff --git a/client/src/standalone/videos/shared/peertube-plugin.ts b/client/src/standalone/videos/shared/peertube-plugin.ts
index 1643ebc9be6..15459394611 100644
--- a/client/src/standalone/videos/shared/peertube-plugin.ts
+++ b/client/src/standalone/videos/shared/peertube-plugin.ts
@@ -19,7 +19,8 @@ export class PeerTubePlugin {
peertubeHelpersFactory: pluginInfo => this.buildPeerTubeHelpers({
pluginInfo,
translations
- })
+ }),
+ backendUrl: getBackendUrl()
})
this.pluginsManager.loadPluginsList(config)
diff --git a/client/src/standalone/videos/shared/player-options-builder.ts b/client/src/standalone/videos/shared/player-options-builder.ts
index 4e3daec57ff..3bd0c199538 100644
--- a/client/src/standalone/videos/shared/player-options-builder.ts
+++ b/client/src/standalone/videos/shared/player-options-builder.ts
@@ -11,7 +11,6 @@ import {
VideoState,
VideoStreamingPlaylistType
} from '@peertube/peertube-models'
-import { HLSOptions, PeerTubePlayerConstructorOptions, PeerTubePlayerLoadOptions, PlayerMode, VideoJSCaption } from '../../../assets/player'
import {
getBoolOrDefault,
getParamString,
@@ -22,12 +21,13 @@ import {
UserLocalStorageKeys,
videoRequiresUserAuth
} from '../../../root-helpers'
+import { HLSOptions, PeerTubePlayerConstructorOptions, PeerTubePlayerLoadOptions, PlayerMode, VideoJSCaption } from '../../player'
import { PeerTubePlugin } from './peertube-plugin'
import { PlayerHTML } from './player-html'
import { PlaylistTracker } from './playlist-tracker'
import { Translations } from './translations'
-import { VideoFetcher } from './video-fetcher'
import { getBackendUrl } from './url'
+import { VideoFetcher } from './video-fetcher'
export class PlayerOptionsBuilder {
private autoplay: boolean
diff --git a/client/src/standalone/videos/vite.config.mjs b/client/src/standalone/videos/vite.config.mjs
index 7c69fd1142e..f7423012800 100644
--- a/client/src/standalone/videos/vite.config.mjs
+++ b/client/src/standalone/videos/vite.config.mjs
@@ -5,8 +5,9 @@ import { dirname } from 'path'
import { fileURLToPath } from 'url'
import checker from 'vite-plugin-checker'
-const __dirname = dirname(fileURLToPath(import.meta.url))
+import { getCSSConfig, getAliasConfig } from '../build-tools/vite-utils.js'
+const __dirname = dirname(fileURLToPath(import.meta.url))
const root = resolve(__dirname, '../../../')
export default defineConfig(({ mode }) => {
@@ -41,26 +42,17 @@ export default defineConfig(({ mode }) => {
},
resolve: {
- alias: [
- { find: /^video.js$/, replacement: resolve(root, './node_modules/video.js/core.js') },
- { find: '@root-helpers', replacement: resolve(root, './src/root-helpers') }
- ],
+ alias: getAliasConfig(root),
},
- css: {
- preprocessorOptions: {
- scss: {
- includePaths: [resolve(root, './src/sass/include')]
- }
- }
- },
+ css: getCSSConfig(root),
build: {
outDir: resolve(root, 'dist', 'standalone', 'videos'),
emptyOutDir: true,
sourcemap: mode === 'development',
- target: [ 'firefox78', 'ios12' ],
+ target: [ 'firefox78', 'ios14' ],
rollupOptions: {
input: {
diff --git a/client/yarn.lock b/client/yarn.lock
index 0ef35537301..9d736b04a86 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -454,6 +454,11 @@
axios "^1.7.4"
uuid "9.0.1"
+"@bufbuild/protobuf@^2.0.0":
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-2.2.3.tgz#9cd136f6b687e63e9b517b3a54211ece942897ee"
+ integrity sha512-tFQoXHJdkEOSwj5tRIZSPNUuXK3RaR7T1nUrPgbYX1pUbvqqaaZAsfo+NXBPsz5rZMSKVFrgK1WL8Q/MSLvprg==
+
"@colors/colors@1.6.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0"
@@ -500,171 +505,86 @@
esquery "^1.6.0"
jsdoc-type-pratt-parser "~4.0.0"
-"@esbuild/aix-ppc64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f"
- integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==
-
"@esbuild/aix-ppc64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz#38848d3e25afe842a7943643cbcd387cc6e13461"
integrity sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==
-"@esbuild/android-arm64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052"
- integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==
-
"@esbuild/android-arm64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz#f592957ae8b5643129fa889c79e69cd8669bb894"
integrity sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==
-"@esbuild/android-arm@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28"
- integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==
-
"@esbuild/android-arm@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.24.2.tgz#72d8a2063aa630308af486a7e5cbcd1e134335b3"
integrity sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==
-"@esbuild/android-x64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e"
- integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==
-
"@esbuild/android-x64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.24.2.tgz#9a7713504d5f04792f33be9c197a882b2d88febb"
integrity sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==
-"@esbuild/darwin-arm64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a"
- integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==
-
"@esbuild/darwin-arm64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz#02ae04ad8ebffd6e2ea096181b3366816b2b5936"
integrity sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==
-"@esbuild/darwin-x64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22"
- integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==
-
"@esbuild/darwin-x64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz#9ec312bc29c60e1b6cecadc82bd504d8adaa19e9"
integrity sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==
-"@esbuild/freebsd-arm64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e"
- integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==
-
"@esbuild/freebsd-arm64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz#5e82f44cb4906d6aebf24497d6a068cfc152fa00"
integrity sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==
-"@esbuild/freebsd-x64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261"
- integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==
-
"@esbuild/freebsd-x64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz#3fb1ce92f276168b75074b4e51aa0d8141ecce7f"
integrity sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==
-"@esbuild/linux-arm64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b"
- integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==
-
"@esbuild/linux-arm64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz#856b632d79eb80aec0864381efd29de8fd0b1f43"
integrity sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==
-"@esbuild/linux-arm@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9"
- integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==
-
"@esbuild/linux-arm@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz#c846b4694dc5a75d1444f52257ccc5659021b736"
integrity sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==
-"@esbuild/linux-ia32@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2"
- integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==
-
"@esbuild/linux-ia32@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz#f8a16615a78826ccbb6566fab9a9606cfd4a37d5"
integrity sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==
-"@esbuild/linux-loong64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df"
- integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==
-
"@esbuild/linux-loong64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz#1c451538c765bf14913512c76ed8a351e18b09fc"
integrity sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==
-"@esbuild/linux-mips64el@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe"
- integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==
-
"@esbuild/linux-mips64el@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz#0846edeefbc3d8d50645c51869cc64401d9239cb"
integrity sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==
-"@esbuild/linux-ppc64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4"
- integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==
-
"@esbuild/linux-ppc64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz#8e3fc54505671d193337a36dfd4c1a23b8a41412"
integrity sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==
-"@esbuild/linux-riscv64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc"
- integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==
-
"@esbuild/linux-riscv64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz#6a1e92096d5e68f7bb10a0d64bb5b6d1daf9a694"
integrity sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==
-"@esbuild/linux-s390x@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de"
- integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==
-
"@esbuild/linux-s390x@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz#ab18e56e66f7a3c49cb97d337cd0a6fea28a8577"
integrity sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==
-"@esbuild/linux-x64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0"
- integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==
-
"@esbuild/linux-x64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz#8140c9b40da634d380b0b29c837a0b4267aff38f"
@@ -675,11 +595,6 @@
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz#65f19161432bafb3981f5f20a7ff45abb2e708e6"
integrity sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==
-"@esbuild/netbsd-x64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047"
- integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==
-
"@esbuild/netbsd-x64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz#7a3a97d77abfd11765a72f1c6f9b18f5396bcc40"
@@ -690,51 +605,26 @@
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz#58b00238dd8f123bfff68d3acc53a6ee369af89f"
integrity sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==
-"@esbuild/openbsd-x64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70"
- integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==
-
"@esbuild/openbsd-x64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz#0ac843fda0feb85a93e288842936c21a00a8a205"
integrity sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==
-"@esbuild/sunos-x64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b"
- integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==
-
"@esbuild/sunos-x64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz#8b7aa895e07828d36c422a4404cc2ecf27fb15c6"
integrity sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==
-"@esbuild/win32-arm64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d"
- integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==
-
"@esbuild/win32-arm64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz#c023afb647cabf0c3ed13f0eddfc4f1d61c66a85"
integrity sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==
-"@esbuild/win32-ia32@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b"
- integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==
-
"@esbuild/win32-ia32@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz#96c356132d2dda990098c8b8b951209c3cd743c2"
integrity sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==
-"@esbuild/win32-x64@0.21.5":
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c"
- integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==
-
"@esbuild/win32-x64@0.24.2":
version "0.24.2"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz#34aa0b52d0fbb1a654b596acfa595f0c7b77a77b"
@@ -1495,29 +1385,6 @@
smtp-server "^3.9.0"
wildstring "1.0.9"
-"@peertube/p2p-media-loader-core@^1.0.20":
- version "1.0.20"
- resolved "https://registry.yarnpkg.com/@peertube/p2p-media-loader-core/-/p2p-media-loader-core-1.0.20.tgz#8e786dd52471a03fc00006d14b150b38fe7c8211"
- integrity sha512-t6yYFcBTqDZSp3U0HqOI9fJzxFgb2C4PoiRI4FPGd28baUbsilO1PQBRwQzvu6wt8zwjzOE8FBpzYa+1gv1Sqg==
- dependencies:
- bittorrent-tracker "^11.1.0"
- debug "^4.3.5"
- esbuild "^0.21.5"
- events "^3.3.0"
- sha.js "^2.4.11"
- simple-peer "^9.11.1"
-
-"@peertube/p2p-media-loader-hlsjs@^1.0.20":
- version "1.0.20"
- resolved "https://registry.yarnpkg.com/@peertube/p2p-media-loader-hlsjs/-/p2p-media-loader-hlsjs-1.0.20.tgz#b6330d5331a70fa3a65ef3c32546b8d88c065749"
- integrity sha512-PZS9h+txV+BX3t5lsh5PZ0ZtOogPJv4GmheQ5etceQZHxRAx2UxcAchMBJsa/sQ5c4CSMsN61Megs9iZ3gWauQ==
- dependencies:
- "@peertube/p2p-media-loader-core" "^1.0.20"
- debug "^4.3.5"
- esbuild "^0.21.5"
- events "^3.3.0"
- m3u8-parser "~4.7.1"
-
"@peertube/xliffmerge@^2.0.3":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@peertube/xliffmerge/-/xliffmerge-2.0.4.tgz#5a80c263ab6f1b15a8b8c3e54317077f0d98e611"
@@ -1609,9 +1476,9 @@
magic-string "^0.30.3"
"@rollup/pluginutils@^5.0.1":
- version "5.1.4"
- resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz#bb94f1f9eaaac944da237767cdfee6c5b2262d4a"
- integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.3.tgz#3001bf1a03f3ad24457591f2c259c8e514e0dbdf"
+ integrity sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==
dependencies:
"@types/estree" "^1.0.0"
estree-walker "^2.0.2"
@@ -1989,7 +1856,7 @@
resolved "https://registry.yarnpkg.com/@types/core-js/-/core-js-2.5.8.tgz#d5c6ec44f2f3328653dce385ae586bd8261f8e85"
integrity sha512-VgnAj6tIAhJhZdJ8/IpxdatM8G4OD3VWGlp6xIxUGENZlpbob9Ty4VVdC1FIEp0aK6DBscDDjyzy5FB60TuNqg==
-"@types/debug@^4.1.5":
+"@types/debug@^4.1.12", "@types/debug@^4.1.5":
version "4.1.12"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917"
integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==
@@ -2997,7 +2864,7 @@ bittorrent-peerid@^1.3.6:
resolved "https://registry.yarnpkg.com/bittorrent-peerid/-/bittorrent-peerid-1.3.6.tgz#3688705a64937a8176ac2ded1178fc7bd91b61db"
integrity sha512-VyLcUjVMEOdSpHaCG/7odvCdLbAB1y3l9A2V6WIje24uV7FkJPrQrH/RrlFmKxP89pFVDEnE+YlHaFujlFIZsg==
-bittorrent-tracker@^11.1.0:
+bittorrent-tracker@^11.2.1:
version "11.2.1"
resolved "https://registry.yarnpkg.com/bittorrent-tracker/-/bittorrent-tracker-11.2.1.tgz#b45ff4bd70c2c582bc60d4a8bb6b5bdcb487df9a"
integrity sha512-SffBgHzNrhn+HBwdRD2st+TYJOs2LhF3ljJFPCYGv592LpGtPxw41UZHTUeY5muWnQl+wopcU8qXM9UEk2WKrA==
@@ -3184,6 +3051,11 @@ browserstack-local@^1.5.1:
ps-tree "=1.2.0"
temp-fs "^0.9.9"
+buffer-builder@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/buffer-builder/-/buffer-builder-0.2.0.tgz#3322cd307d8296dab1f604618593b261a3fade8f"
+ integrity sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==
+
buffer-crc32@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-1.0.0.tgz#a10993b9055081d55304bd9feb4a072de179f405"
@@ -3544,6 +3416,11 @@ colorette@^2.0.20:
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
+colorjs.io@^0.5.0:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/colorjs.io/-/colorjs.io-0.5.2.tgz#63b20139b007591ebc3359932bef84628eb3fcef"
+ integrity sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==
+
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
@@ -3811,7 +3688,7 @@ data-view-byte-offset@^1.0.1:
es-errors "^1.3.0"
is-data-view "^1.0.1"
-debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.6, debug@^4.3.7:
+debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.6, debug@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
@@ -3832,7 +3709,7 @@ debug@^3.2.7:
dependencies:
ms "^2.1.1"
-debug@~4.3.1, debug@~4.3.2:
+debug@^4.3.7, debug@~4.3.1, debug@~4.3.2:
version "4.3.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==
@@ -4022,10 +3899,10 @@ dom-walk@^0.1.0:
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84"
integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==
-domain-browser@4.22.0:
- version "4.22.0"
- resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.22.0.tgz#6ddd34220ec281f9a65d3386d267ddd35c491f9f"
- integrity sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==
+domain-browser@^4.22.0:
+ version "4.23.0"
+ resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.23.0.tgz#427ebb91efcb070f05cffdfb8a4e9a6c25f8c94b"
+ integrity sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==
domelementtype@^2.3.0:
version "2.3.0"
@@ -4129,9 +4006,9 @@ electron-to-chromium@^1.5.73:
integrity sha512-C3PN4aydfW91Natdyd449Kw+BzhLmof6tzy5W1pFC5SpQxVXT+oyiyOG9AgYYSN9OdA/ik3YkCrpwqI8ug5Tug==
elliptic@^6.5.3, elliptic@^6.5.5:
- version "6.6.1"
- resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06"
- integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==
+ version "6.6.0"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.0.tgz#5919ec723286c1edf28685aa89261d4761afa210"
+ integrity sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==
dependencies:
bn.js "^4.11.9"
brorand "^1.1.0"
@@ -4354,35 +4231,6 @@ esbuild@0.24.2, esbuild@^0.24.2:
"@esbuild/win32-ia32" "0.24.2"
"@esbuild/win32-x64" "0.24.2"
-esbuild@^0.21.3, esbuild@^0.21.5:
- version "0.21.5"
- resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d"
- integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==
- optionalDependencies:
- "@esbuild/aix-ppc64" "0.21.5"
- "@esbuild/android-arm" "0.21.5"
- "@esbuild/android-arm64" "0.21.5"
- "@esbuild/android-x64" "0.21.5"
- "@esbuild/darwin-arm64" "0.21.5"
- "@esbuild/darwin-x64" "0.21.5"
- "@esbuild/freebsd-arm64" "0.21.5"
- "@esbuild/freebsd-x64" "0.21.5"
- "@esbuild/linux-arm" "0.21.5"
- "@esbuild/linux-arm64" "0.21.5"
- "@esbuild/linux-ia32" "0.21.5"
- "@esbuild/linux-loong64" "0.21.5"
- "@esbuild/linux-mips64el" "0.21.5"
- "@esbuild/linux-ppc64" "0.21.5"
- "@esbuild/linux-riscv64" "0.21.5"
- "@esbuild/linux-s390x" "0.21.5"
- "@esbuild/linux-x64" "0.21.5"
- "@esbuild/netbsd-x64" "0.21.5"
- "@esbuild/openbsd-x64" "0.21.5"
- "@esbuild/sunos-x64" "0.21.5"
- "@esbuild/win32-arm64" "0.21.5"
- "@esbuild/win32-ia32" "0.21.5"
- "@esbuild/win32-x64" "0.21.5"
-
escalade@^3.1.1, escalade@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
@@ -5031,11 +4879,6 @@ gensync@^1.0.0-beta.2:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
-get-browser-rtc@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz#d1494e299b00f33fc8e9d6d3343ba4ba99711a2c"
- integrity sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==
-
get-caller-file@^2.0.1, get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
@@ -5356,12 +5199,12 @@ hash-base@^3.0.0:
safe-buffer "^5.2.0"
hash-base@~3.0, hash-base@~3.0.4:
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.5.tgz#52480e285395cf7fba17dc4c9e47acdc7f248a8a"
- integrity sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918"
+ integrity sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==
dependencies:
- inherits "^2.0.4"
- safe-buffer "^5.2.1"
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
hash.js@^1.0.0, hash.js@^1.0.3:
version "1.1.7"
@@ -6427,22 +6270,20 @@ m3u8-parser@4.8.0:
"@videojs/vhs-utils" "^3.0.5"
global "^4.4.0"
-m3u8-parser@~4.7.1:
- version "4.7.1"
- resolved "https://registry.yarnpkg.com/m3u8-parser/-/m3u8-parser-4.7.1.tgz#d6df2c940bb19a01112a04ccc4ff44886a945305"
- integrity sha512-pbrQwiMiq+MmI9bl7UjtPT3AK603PV9bogNlr83uC+X9IoxqL5E4k7kU7fMQ0dpRgxgeSMygqUa0IMLQNXLBNA==
- dependencies:
- "@babel/runtime" "^7.12.5"
- "@videojs/vhs-utils" "^3.0.5"
- global "^4.4.0"
-
-magic-string@0.30.17, magic-string@^0.30.12, magic-string@^0.30.3:
+magic-string@0.30.17, magic-string@^0.30.12:
version "0.30.17"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453"
integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==
dependencies:
"@jridgewell/sourcemap-codec" "^1.5.0"
+magic-string@^0.30.3:
+ version "0.30.12"
+ resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.12.tgz#9eb11c9d072b9bcb4940a5b2c2e1a217e4ee1a60"
+ integrity sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==
+ dependencies:
+ "@jridgewell/sourcemap-codec" "^1.5.0"
+
mailparser-mit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/mailparser-mit/-/mailparser-mit-1.0.0.tgz#19df8436c2a02e1d34a03ec518a2eb065e0a94a4"
@@ -6855,6 +6696,11 @@ mux.js@6.0.1:
"@babel/runtime" "^7.11.2"
global "^4.4.0"
+nano-md5@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/nano-md5/-/nano-md5-1.0.5.tgz#99d155e95ccaadc4096a309292a0df1b5190514e"
+ integrity sha512-1VAOX0EiuwAdCMGpnglxp9r6ylm+gXwQi+UPAnc/Oj1tLLJ8D1I8rLZeiO4MWsUAqH8tuBAHweT1LYSrDfJlPg==
+
nanoid@^3.3.8:
version "3.3.8"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf"
@@ -6888,9 +6734,9 @@ ngx-uploadx@^7.0.0:
tslib "^2.3.0"
node-abi@^3.3.0:
- version "3.74.0"
- resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.74.0.tgz#5bfb4424264eaeb91432d2adb9da23c63a301ed0"
- integrity sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==
+ version "3.71.0"
+ resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.71.0.tgz#52d84bbcd8575efb71468fbaa1f9a49b2c242038"
+ integrity sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==
dependencies:
semver "^7.3.5"
@@ -6946,9 +6792,9 @@ node-gyp-build-optional-packages@5.2.2:
detect-libc "^2.0.1"
node-gyp-build@^4.3.0:
- version "4.8.4"
- resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8"
- integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==
+ version "4.8.3"
+ resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.3.tgz#9187216d24dbee29e44eb20d2ebf62a296bbea1a"
+ integrity sha512-EMS95CMJzdoSKoIiXo8pxKoL8DYxwIZXYlLmgPb8KUv794abpnLK6ynsCAWNliOjREKruYKdzbh76HHYUHX7nw==
node-gyp@^11.0.0:
version "11.0.0"
@@ -6982,9 +6828,9 @@ node-request-interceptor@^0.6.3:
strict-event-emitter "^0.1.0"
node-stdlib-browser@^1.2.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/node-stdlib-browser/-/node-stdlib-browser-1.3.0.tgz#6e04d149f9abfc345a2271b2820a75df0f9cd7de"
- integrity sha512-g/koYzOr9Fb1Jc+tHUHlFd5gODjGn48tHexUK8q6iqOVriEgSnd3/1T7myBYc+0KBVze/7F7n65ec9rW6OD7xw==
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/node-stdlib-browser/-/node-stdlib-browser-1.2.1.tgz#888fa104914af94143ca4d8a8980fe0ed242d2d1"
+ integrity sha512-dZezG3D88Lg22DwyjsDuUs7cCT/XGr8WwJgg/S3ZnkcWuPet2Tt/W1d2Eytb1Z73JpZv+XVCDI5TWv6UMRq0Gg==
dependencies:
assert "^2.0.0"
browser-resolve "^2.0.0"
@@ -6994,7 +6840,7 @@ node-stdlib-browser@^1.2.0:
constants-browserify "^1.0.0"
create-require "^1.1.1"
crypto-browserify "^3.11.0"
- domain-browser "4.22.0"
+ domain-browser "^4.22.0"
events "^3.0.0"
https-browserify "^1.0.0"
isomorphic-timers-promises "^1.0.1"
@@ -7321,6 +7167,23 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+p2p-media-loader-core@2.1.2, p2p-media-loader-core@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/p2p-media-loader-core/-/p2p-media-loader-core-2.1.2.tgz#27bcb7b95cba76d00a681ce21bffaf41f418514e"
+ integrity sha512-fAeoXANKFRnHF17a706Bd6WtMdi5a9Ac78b39TBaGBWLFGfNWVj249ysuY8c5beLlgpGNnl5J4w9VH+I1UH2nQ==
+ dependencies:
+ "@types/debug" "^4.1.12"
+ bittorrent-tracker "^11.2.1"
+ debug "^4.4.0"
+ nano-md5 "^1.0.5"
+
+p2p-media-loader-hlsjs@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/p2p-media-loader-hlsjs/-/p2p-media-loader-hlsjs-2.1.2.tgz#a476cce7e196426b45c30a3669c62b0d21f1616e"
+ integrity sha512-97iCj6qlyHbBDTDHpbyuKejBdljA0gahq0Fa2B7GhiIJNqPN4nJe0KzycE1Yket8JpDKqGGE1747PpTSz2qLaA==
+ dependencies:
+ p2p-media-loader-core "2.1.2"
+
pac-proxy-agent@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.1.0.tgz#da7c3b5c4cccc6655aaafb701ae140fb23f15df2"
@@ -7620,7 +7483,7 @@ postcss-value-parser@^4.2.0:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
-postcss@^8.4.32, postcss@^8.4.43, postcss@^8.4.49, postcss@^8.5.1:
+postcss@^8.4.32, postcss@^8.4.49, postcss@^8.5.1:
version "8.5.1"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.1.tgz#e2272a1f8a807fafa413218245630b5db10a3214"
integrity sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==
@@ -7812,6 +7675,11 @@ queue-microtask@^1.2.2, queue-microtask@^1.2.3:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+queue-tick@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142"
+ integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==
+
quick-lru@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
@@ -8119,7 +7987,7 @@ rollup@4.30.1:
"@rollup/rollup-win32-x64-msvc" "4.30.1"
fsevents "~2.3.2"
-rollup@^4.20.0, rollup@^4.23.0:
+rollup@^4.23.0:
version "4.34.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.34.1.tgz#dcc318abee12e23dae4003af733c1987d7baca8e"
integrity sha512-iYZ/+PcdLYSGfH3S+dGahlW/RWmsqDhLgj1BT9DH/xXJ0ggZN7xkdP9wipPNjjNLczI+fmMLmTB9pye+d2r4GQ==
@@ -8171,7 +8039,7 @@ rust-result@^1.0.0:
dependencies:
individual "^2.0.0"
-rxjs@7.8.1, rxjs@^7.3.0, rxjs@^7.8.1:
+rxjs@7.8.1, rxjs@^7.3.0, rxjs@^7.4.0, rxjs@^7.8.1:
version "7.8.1"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
@@ -8238,6 +8106,141 @@ safe-stable-stringify@^2.3.1:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+sass-embedded-android-arm64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.83.4.tgz#60af9d787e74276af95e4a1a1507567435bc61d2"
+ integrity sha512-tgX4FzmbVqnQmD67ZxQDvI+qFNABrboOQgwsG05E5bA/US42zGajW9AxpECJYiMXVOHmg+d81ICbjb0fsVHskw==
+
+sass-embedded-android-arm@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-android-arm/-/sass-embedded-android-arm-1.83.4.tgz#960953d094bf28c3e10a2e0ebd14459d4ec6e2d2"
+ integrity sha512-9Z4pJAOgEkXa3VDY/o+U6l5XvV0mZTJcSl0l/mSPHihjAHSpLYnOW6+KOWeM8dxqrsqTYcd6COzhanI/a++5Gw==
+
+sass-embedded-android-ia32@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-android-ia32/-/sass-embedded-android-ia32-1.83.4.tgz#2293cb9920181094edfa477ba503f1f187d21624"
+ integrity sha512-RsFOziFqPcfZXdFRULC4Ayzy9aK6R6FwQ411broCjlOBX+b0gurjRadkue3cfUEUR5mmy0KeCbp7zVKPLTK+5Q==
+
+sass-embedded-android-riscv64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.83.4.tgz#84f86f2e96955a415343a2f24bae1af7bde26e5f"
+ integrity sha512-EHwh0nmQarBBrMRU928eTZkFGx19k/XW2YwbPR4gBVdWLkbTgCA5aGe8hTE6/1zStyx++3nDGvTZ78+b/VvvLg==
+
+sass-embedded-android-x64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-android-x64/-/sass-embedded-android-x64-1.83.4.tgz#8db3bb08b941889918f8435a97487cd84e7fd748"
+ integrity sha512-0PgQNuPWYy1jEOEPDVsV89KfqOsMLIp9CSbjBY7jRcwRhyVAcigqrUG6bDeNtojHUYKA1kU+Eh/85WxOHUOgBw==
+
+sass-embedded-darwin-arm64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.83.4.tgz#d0f3d82eea999ab0ae7ec8abd7fa364f0defc75e"
+ integrity sha512-rp2ywymWc3nymnSnAFG5R/8hvxWCsuhK3wOnD10IDlmNB7o4rzKby1c+2ZfpQGowlYGWsWWTgz8FW2qzmZsQRw==
+
+sass-embedded-darwin-x64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.83.4.tgz#cd2ac7f209fe823a8a5fc1a064cdfe2833680034"
+ integrity sha512-kLkN2lXz9PCgGfDS8Ev5YVcl/V2173L6379en/CaFuJJi7WiyPgBymW7hOmfCt4uO4R1y7CP2Uc08DRtZsBlAA==
+
+sass-embedded-linux-arm64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.83.4.tgz#057adf6e337357787331d40714cb8bba4a96dafe"
+ integrity sha512-E0zjsZX2HgESwyqw31EHtI39DKa7RgK7nvIhIRco1d0QEw227WnoR9pjH3M/ZQy4gQj3GKilOFHM5Krs/omeIA==
+
+sass-embedded-linux-arm@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.83.4.tgz#aea8b56f3844633f0bfaf13e0694c79511218fc0"
+ integrity sha512-nL90ryxX2lNmFucr9jYUyHHx21AoAgdCL1O5Ltx2rKg2xTdytAGHYo2MT5S0LIeKLa/yKP/hjuSvrbICYNDvtA==
+
+sass-embedded-linux-ia32@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-linux-ia32/-/sass-embedded-linux-ia32-1.83.4.tgz#2cedba9f41be61ded3cede5abd16f8ec163d7f46"
+ integrity sha512-ew5HpchSzgAYbQoriRh8QhlWn5Kw2nQ2jHoV9YLwGKe3fwwOWA0KDedssvDv7FWnY/FCqXyymhLd6Bxae4Xquw==
+
+sass-embedded-linux-musl-arm64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.83.4.tgz#1c5f50c9df93abce7d5ffb4d86eed65b8ffba2f4"
+ integrity sha512-IzMgalf6MZOxgp4AVCgsaWAFDP/IVWOrgVXxkyhw29fyAEoSWBJH4k87wyPhEtxSuzVHLxKNbc8k3UzdWmlBFg==
+
+sass-embedded-linux-musl-arm@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.83.4.tgz#00f241dbc750ee73242bfde1ec5d64ef2d5d7956"
+ integrity sha512-0RrJRwMrmm+gG0VOB5b5Cjs7Sd+lhqpQJa6EJNEaZHljJokEfpE5GejZsGMRMIQLxEvVphZnnxl6sonCGFE/QQ==
+
+sass-embedded-linux-musl-ia32@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-ia32/-/sass-embedded-linux-musl-ia32-1.83.4.tgz#27537a309d39f8e35a7dba34a3edc29a3ee16adf"
+ integrity sha512-LLb4lYbcxPzX4UaJymYXC+WwokxUlfTJEFUv5VF0OTuSsHAGNRs/rslPtzVBTvMeG9TtlOQDhku1F7G6iaDotA==
+
+sass-embedded-linux-musl-riscv64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.83.4.tgz#a32edf2ddb7f7d9b526e971e80cadef1e025cce8"
+ integrity sha512-zoKlPzD5Z13HKin1UGR74QkEy+kZEk2AkGX5RelRG494mi+IWwRuWCppXIovor9+BQb9eDWPYPoMVahwN5F7VA==
+
+sass-embedded-linux-musl-x64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.83.4.tgz#668b90b80bf35830c2f1ea2a47557d5e60842598"
+ integrity sha512-hB8+/PYhfEf2zTIcidO5Bpof9trK6WJjZ4T8g2MrxQh8REVtdPcgIkoxczRynqybf9+fbqbUwzXtiUao2GV+vQ==
+
+sass-embedded-linux-riscv64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.83.4.tgz#b7718df2adf1cbcb4c26609215018dd2e8bab595"
+ integrity sha512-83fL4n+oeDJ0Y4KjASmZ9jHS1Vl9ESVQYHMhJE0i4xDi/P3BNarm2rsKljq/QtrwGpbqwn8ujzOu7DsNCMDSHA==
+
+sass-embedded-linux-x64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.83.4.tgz#52e61bd582dfc56b8f638f2b9cfdb8a53db1e57e"
+ integrity sha512-NlnGdvCmTD5PK+LKXlK3sAuxOgbRIEoZfnHvxd157imCm/s2SYF/R28D0DAAjEViyI8DovIWghgbcqwuertXsA==
+
+sass-embedded-win32-arm64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.83.4.tgz#b6ca8f65177e24770e87e43ffea5868fea34de27"
+ integrity sha512-J2BFKrEaeSrVazU2qTjyQdAk+MvbzJeTuCET0uAJEXSKtvQ3AzxvzndS7LqkDPbF32eXAHLw8GVpwcBwKbB3Uw==
+
+sass-embedded-win32-ia32@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-win32-ia32/-/sass-embedded-win32-ia32-1.83.4.tgz#94f8da72e253532f8d857516b99e1caf61e7b08f"
+ integrity sha512-uPAe9T/5sANFhJS5dcfAOhOJy8/l2TRYG4r+UO3Wp4yhqbN7bggPvY9c7zMYS0OC8tU/bCvfYUDFHYMCl91FgA==
+
+sass-embedded-win32-x64@1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.83.4.tgz#2179d4e2fc2f9086aecd64209a2d84f7d8e9edbe"
+ integrity sha512-C9fkDY0jKITdJFij4UbfPFswxoXN9O/Dr79v17fJnstVwtUojzVJWKHUXvF0Zg2LIR7TCc4ju3adejKFxj7ueA==
+
+sass-embedded@^1.83.4:
+ version "1.83.4"
+ resolved "https://registry.yarnpkg.com/sass-embedded/-/sass-embedded-1.83.4.tgz#9b05cdc22ae71a1b27b5996a39054ba59bebc04a"
+ integrity sha512-Hf2burRA/y5PGxsg6jB9UpoK/xZ6g/pgrkOcdl6j+rRg1Zj8XhGKZ1MTysZGtTPUUmiiErqzkP5+Kzp95yv9GQ==
+ dependencies:
+ "@bufbuild/protobuf" "^2.0.0"
+ buffer-builder "^0.2.0"
+ colorjs.io "^0.5.0"
+ immutable "^5.0.2"
+ rxjs "^7.4.0"
+ supports-color "^8.1.1"
+ sync-child-process "^1.0.2"
+ varint "^6.0.0"
+ optionalDependencies:
+ sass-embedded-android-arm "1.83.4"
+ sass-embedded-android-arm64 "1.83.4"
+ sass-embedded-android-ia32 "1.83.4"
+ sass-embedded-android-riscv64 "1.83.4"
+ sass-embedded-android-x64 "1.83.4"
+ sass-embedded-darwin-arm64 "1.83.4"
+ sass-embedded-darwin-x64 "1.83.4"
+ sass-embedded-linux-arm "1.83.4"
+ sass-embedded-linux-arm64 "1.83.4"
+ sass-embedded-linux-ia32 "1.83.4"
+ sass-embedded-linux-musl-arm "1.83.4"
+ sass-embedded-linux-musl-arm64 "1.83.4"
+ sass-embedded-linux-musl-ia32 "1.83.4"
+ sass-embedded-linux-musl-riscv64 "1.83.4"
+ sass-embedded-linux-musl-x64 "1.83.4"
+ sass-embedded-linux-riscv64 "1.83.4"
+ sass-embedded-linux-x64 "1.83.4"
+ sass-embedded-win32-arm64 "1.83.4"
+ sass-embedded-win32-ia32 "1.83.4"
+ sass-embedded-win32-x64 "1.83.4"
+
sass@1.83.1:
version "1.83.1"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.83.1.tgz#dee1ab94b47a6f9993d3195d36f556bcbda64846"
@@ -8415,19 +8418,6 @@ simple-get@^4.0.0:
once "^1.3.1"
simple-concat "^1.0.0"
-simple-peer@^9.11.1:
- version "9.11.1"
- resolved "https://registry.yarnpkg.com/simple-peer/-/simple-peer-9.11.1.tgz#9814d5723f821b778b7fb011bdefcbd1e788e6cc"
- integrity sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==
- dependencies:
- buffer "^6.0.3"
- debug "^4.3.2"
- err-code "^3.0.1"
- get-browser-rtc "^1.1.0"
- queue-microtask "^1.2.3"
- randombytes "^2.1.0"
- readable-stream "^3.6.0"
-
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
@@ -8628,7 +8618,29 @@ stream-http@^3.2.0:
readable-stream "^3.6.0"
xtend "^4.0.2"
-streamx@^2.15.0, streamx@^2.17.0, streamx@^2.20.1, streamx@^2.21.0:
+streamx@^2.15.0:
+ version "2.18.0"
+ resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.18.0.tgz#5bc1a51eb412a667ebfdcd4e6cf6a6fc65721ac7"
+ integrity sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==
+ dependencies:
+ fast-fifo "^1.3.2"
+ queue-tick "^1.0.1"
+ text-decoder "^1.1.0"
+ optionalDependencies:
+ bare-events "^2.2.0"
+
+streamx@^2.17.0, streamx@^2.20.1:
+ version "2.20.2"
+ resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.20.2.tgz#6a8911959d6f307c19781a1d19ecd94b5f042d78"
+ integrity sha512-aDGDLU+j9tJcUdPGOaHmVF1u/hhI+CsGkT02V3OKlHDV7IukOI+nTWAGkiZEKCO35rWN1wIr4tS7YFr1f4qSvA==
+ dependencies:
+ fast-fifo "^1.3.2"
+ queue-tick "^1.0.1"
+ text-decoder "^1.1.0"
+ optionalDependencies:
+ bare-events "^2.2.0"
+
+streamx@^2.21.0:
version "2.22.0"
resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.22.0.tgz#cd7b5e57c95aaef0ff9b2aef7905afa62ec6e4a7"
integrity sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==
@@ -8897,6 +8909,18 @@ symbol-observable@4.0.0:
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205"
integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==
+sync-child-process@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/sync-child-process/-/sync-child-process-1.0.2.tgz#45e7c72e756d1243e80b547ea2e17957ab9e367f"
+ integrity sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==
+ dependencies:
+ sync-message-port "^1.0.0"
+
+sync-message-port@^1.0.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/sync-message-port/-/sync-message-port-1.1.3.tgz#6055c565ee8c81d2f9ee5aae7db757e6d9088c0c"
+ integrity sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==
+
synckit@^0.9.1:
version "0.9.2"
resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62"
@@ -9406,6 +9430,11 @@ validate-npm-package-name@^6.0.0:
resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-6.0.0.tgz#3add966c853cfe36e0e8e6a762edd72ae6f1d6ac"
integrity sha512-d7KLgL1LD3U3fgnvWEY1cQXoO/q6EQ1BSz48Sa149V/5zVTAbgmZIpyI8TRi6U9/JNyeYLlTKsEMPtLC27RFUg==
+varint@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/varint/-/varint-6.0.0.tgz#9881eb0ce8feaea6512439d19ddf84bf551661d0"
+ integrity sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==
+
"video.js@^6 || ^7", video.js@^7.19.2:
version "7.21.6"
resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.21.6.tgz#a42d817c42d8d91538b72197a0874aeb01c76ce9"
@@ -9437,10 +9466,10 @@ videojs-vtt.js@^0.15.5:
dependencies:
global "^4.3.1"
-vite-plugin-checker@^0.7.2:
- version "0.7.2"
- resolved "https://registry.yarnpkg.com/vite-plugin-checker/-/vite-plugin-checker-0.7.2.tgz#093ffdf9ccf51b2c9eab7101480bd0217ae99536"
- integrity sha512-xeYeJbG0gaCaT0QcUC4B2Zo4y5NR8ZhYenc5gPbttrZvraRFwkEADCYwq+BfEHl9zYz7yf85TxsiGoYwyyIjhw==
+vite-plugin-checker@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/vite-plugin-checker/-/vite-plugin-checker-0.8.0.tgz#33419857a623b35c9483e4f603d4ca8b6984acde"
+ integrity sha512-UA5uzOGm97UvZRTdZHiQVYFnd86AVn8EVaD4L3PoVzxH+IZSfaAw14WGFwX9QS23UW3lV/5bVKZn6l0w+q9P0g==
dependencies:
"@babel/code-frame" "^7.12.13"
ansi-escapes "^4.3.0"
@@ -9457,15 +9486,15 @@ vite-plugin-checker@^0.7.2:
vscode-languageserver-textdocument "^1.0.1"
vscode-uri "^3.0.2"
-vite-plugin-node-polyfills@^0.22.0:
- version "0.22.0"
- resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.22.0.tgz#d0afcf82eb985fc02244620d7cec1ddd1c6e0864"
- integrity sha512-F+G3LjiGbG8QpbH9bZ//GSBr9i1InSTkaulfUHFa9jkLqVGORFBoqc2A/Yu5Mmh1kNAbiAeKeK+6aaQUf3x0JA==
+vite-plugin-node-polyfills@^0.23.0:
+ version "0.23.0"
+ resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.23.0.tgz#99d0d1524fa75ce5c7bb1fc8af30283379e9c684"
+ integrity sha512-4n+Ys+2bKHQohPBKigFlndwWQ5fFKwaGY6muNDMTb0fSQLyBzS+jjUNRZG9sKF0S/Go4ApG6LFnUGopjkILg3w==
dependencies:
"@rollup/plugin-inject" "^5.0.5"
node-stdlib-browser "^1.2.0"
-vite@6.0.11:
+vite@6.0.11, vite@^6.0.11:
version "6.0.11"
resolved "https://registry.yarnpkg.com/vite/-/vite-6.0.11.tgz#224497e93e940b34c3357c9ebf2ec20803091ed8"
integrity sha512-4VL9mQPKoHy4+FE0NnRE/kbY51TOfaknxAjt3fJbGJxhIpBZiqVzlZDEesWWsuREXHwNdAoOFZ9MkPEVXczHwg==
@@ -9476,17 +9505,6 @@ vite@6.0.11:
optionalDependencies:
fsevents "~2.3.3"
-vite@^5.3.1:
- version "5.4.14"
- resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.14.tgz#ff8255edb02134df180dcfca1916c37a6abe8408"
- integrity sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==
- dependencies:
- esbuild "^0.21.3"
- postcss "^8.4.43"
- rollup "^4.20.0"
- optionalDependencies:
- fsevents "~2.3.3"
-
vm-browserify@^1.0.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
diff --git a/packages/node-utils/src/crypto.ts b/packages/node-utils/src/crypto.ts
index 388d7557468..f4199f88416 100644
--- a/packages/node-utils/src/crypto.ts
+++ b/packages/node-utils/src/crypto.ts
@@ -7,3 +7,7 @@ export function sha256 (str: string | Buffer, encoding: BinaryToTextEncoding = '
export function sha1 (str: string | Buffer, encoding: BinaryToTextEncoding = 'hex') {
return createHash('sha1').update(str).digest(encoding)
}
+
+export function md5 (str: string | Buffer, encoding: BinaryToTextEncoding = 'hex') {
+ return createHash('md5').update(str).digest(encoding)
+}
diff --git a/packages/tests/src/api/object-storage/videos.ts b/packages/tests/src/api/object-storage/videos.ts
index bbfaab3ebe8..3c9e89e1aa9 100644
--- a/packages/tests/src/api/object-storage/videos.ts
+++ b/packages/tests/src/api/object-storage/videos.ts
@@ -20,7 +20,7 @@ import { generateHighBitrateVideo } from '@tests/shared/generate.js'
import { MockObjectStorageProxy } from '@tests/shared/mock-servers/mock-object-storage.js'
import { SQLCommand } from '@tests/shared/sql-command.js'
import { checkPlaylistInfohash } from '@tests/shared/streaming-playlists.js'
-import { checkWebTorrentWorks } from '@tests/shared/webtorrent.js'
+import { checkWebTorrentWorks } from '@tests/shared/p2p.js'
import bytes from 'bytes'
import { expect } from 'chai'
import { stat } from 'fs/promises'
diff --git a/packages/tests/src/api/server/tracker.ts b/packages/tests/src/api/server/tracker.ts
index 58e99ff65b7..9f703e6c32d 100644
--- a/packages/tests/src/api/server/tracker.ts
+++ b/packages/tests/src/api/server/tracker.ts
@@ -7,7 +7,7 @@ import {
PeerTubeServer,
setAccessTokensToServers
} from '@peertube/peertube-server-commands'
-import { magnetUriDecode, magnetUriEncode } from '@tests/shared/webtorrent.js'
+import { magnetUriDecode, magnetUriEncode } from '@tests/shared/p2p.js'
import WebTorrent from 'webtorrent'
describe('Test tracker', function () {
diff --git a/packages/tests/src/api/transcoding/transcoder.ts b/packages/tests/src/api/transcoding/transcoder.ts
index fb8099fd862..e1f9e05e967 100644
--- a/packages/tests/src/api/transcoding/transcoder.ts
+++ b/packages/tests/src/api/transcoding/transcoder.ts
@@ -18,7 +18,7 @@ import {
waitJobs
} from '@peertube/peertube-server-commands'
import { canDoQuickTranscode } from '@peertube/peertube-server/core/lib/transcoding/transcoding-quick-transcode.js'
-import { checkWebTorrentWorks } from '@tests/shared/webtorrent.js'
+import { checkWebTorrentWorks } from '@tests/shared/p2p.js'
import { expect } from 'chai'
describe('Test video transcoding', function () {
diff --git a/packages/tests/src/api/videos/multiple-servers.ts b/packages/tests/src/api/videos/multiple-servers.ts
index f2fd483a7da..de021dcf959 100644
--- a/packages/tests/src/api/videos/multiple-servers.ts
+++ b/packages/tests/src/api/videos/multiple-servers.ts
@@ -17,7 +17,7 @@ import {
import { dateIsValid, testImageGeneratedByFFmpeg } from '@tests/shared/checks.js'
import { checkTmpIsEmpty } from '@tests/shared/directories.js'
import { checkVideoFilesWereRemoved, completeVideoCheck, saveVideoInServers } from '@tests/shared/videos.js'
-import { checkWebTorrentWorks } from '@tests/shared/webtorrent.js'
+import { checkWebTorrentWorks } from '@tests/shared/p2p.js'
import Bluebird from 'bluebird'
import { expect } from 'chai'
import request from 'supertest'
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 5577dfdb550..0b5c3f27be2 100644
--- a/packages/tests/src/api/videos/video-static-file-privacy.ts
+++ b/packages/tests/src/api/videos/video-static-file-privacy.ts
@@ -16,7 +16,7 @@ import {
} from '@peertube/peertube-server-commands'
import { expectStartWith } from '@tests/shared/checks.js'
import { checkVideoFileTokenReinjection } from '@tests/shared/streaming-playlists.js'
-import { magnetUriDecode, parseTorrentVideo } from '@tests/shared/webtorrent.js'
+import { magnetUriDecode, parseTorrentVideo } from '@tests/shared/p2p.js'
import { expect } from 'chai'
describe('Test video static file privacy', function () {
diff --git a/packages/tests/src/cli/update-host.ts b/packages/tests/src/cli/update-host.ts
index 30a7b17e4cf..10022086fd3 100644
--- a/packages/tests/src/cli/update-host.ts
+++ b/packages/tests/src/cli/update-host.ts
@@ -12,7 +12,7 @@ import {
setDefaultVideoChannel,
waitJobs
} from '@peertube/peertube-server-commands'
-import { parseTorrentVideo } from '@tests/shared/webtorrent.js'
+import { parseTorrentVideo } from '@tests/shared/p2p.js'
import { VideoPlaylistPrivacy } from '@peertube/peertube-models'
describe('Test update host CLI', function () {
diff --git a/packages/tests/src/shared/live.ts b/packages/tests/src/shared/live.ts
index 179e49336c5..7507098e8db 100644
--- a/packages/tests/src/shared/live.ts
+++ b/packages/tests/src/shared/live.ts
@@ -2,14 +2,13 @@
import { getVideoStreamDimensionsInfo, getVideoStreamFPS } from '@peertube/peertube-ffmpeg'
import { LiveVideo, VideoResolution, VideoStreamingPlaylistType } from '@peertube/peertube-models'
-import { sha1 } from '@peertube/peertube-node-utils'
import { ObjectStorageCommand, PeerTubeServer } from '@peertube/peertube-server-commands'
import { expect } from 'chai'
import { pathExists } from 'fs-extra/esm'
import { readdir } from 'fs/promises'
import { join } from 'path'
import { SQLCommand } from './sql-command.js'
-import { checkLiveSegmentHash, checkResolutionsInMasterPlaylist } from './streaming-playlists.js'
+import { checkLiveSegmentHash, checkPlaylistInfohash, checkResolutionsInMasterPlaylist } from './streaming-playlists.js'
async function checkLiveCleanup (options: {
server: PeerTubeServer
@@ -169,13 +168,10 @@ async function testLiveVideoResolutions (options: {
hlsPlaylist,
withRetry: !!objectStorage // With object storage, the request may fail because of inconsistent data in S3
})
+ }
- if (originServer.internalServerNumber === server.internalServerNumber) {
- const infohash = sha1(`2${hlsPlaylist.playlistUrl}+V${i}`)
- const dbInfohashes = await sqlCommand.getPlaylistInfohash(hlsPlaylist.id)
-
- expect(dbInfohashes).to.include(infohash)
- }
+ if (originServer.internalServerNumber === server.internalServerNumber) {
+ await checkPlaylistInfohash({ video, sqlCommand, files: resolutions.map(r => ({ resolution: { id: r } })) })
}
}
}
diff --git a/packages/tests/src/shared/webtorrent.ts b/packages/tests/src/shared/p2p.ts
similarity index 100%
rename from packages/tests/src/shared/webtorrent.ts
rename to packages/tests/src/shared/p2p.ts
diff --git a/packages/tests/src/shared/streaming-playlists.ts b/packages/tests/src/shared/streaming-playlists.ts
index 35229db86e7..83f51788c3d 100644
--- a/packages/tests/src/shared/streaming-playlists.ts
+++ b/packages/tests/src/shared/streaming-playlists.ts
@@ -10,14 +10,14 @@ import {
VideoStreamingPlaylist,
VideoStreamingPlaylistType
} from '@peertube/peertube-models'
-import { sha1, sha256 } from '@peertube/peertube-node-utils'
+import { md5, sha256 } from '@peertube/peertube-node-utils'
import { makeRawRequest, PeerTubeServer } from '@peertube/peertube-server-commands'
import { expect } from 'chai'
import { basename, dirname, join } from 'path'
import { expectStartWith } from './checks.js'
+import { checkWebTorrentWorks } from './p2p.js'
import { SQLCommand } from './sql-command.js'
-import { hlsInfohashExist } from './tracker.js'
-import { checkWebTorrentWorks } from './webtorrent.js'
+import { checkTrackerInfohash } from './tracker.js'
export async function checkSegmentHash (options: {
server: PeerTubeServer
@@ -72,16 +72,25 @@ export async function checkLiveSegmentHash (options: {
export async function checkPlaylistInfohash (options: {
video: VideoDetails
sqlCommand: SQLCommand
- files: unknown[]
+ files: { resolution: { id: number } }[]
}) {
const { sqlCommand, video, files } = options
const hls = getHLS(video)
+ const version = 2
+ const hash = (input: string) => btoa(md5(input, 'binary').slice(1))
+
for (let i = 0; i < files.length; i++) {
- const infohash = sha1(`${2 + hls.playlistUrl}+V${i}`)
+ const str = files[0].resolution.id === VideoResolution.H_NOVIDEO && files.length !== 0
+ ? `v${version}-${hls.playlistUrl}-secondary-0`
+ : `v${version}-${hls.playlistUrl}-main-${i}`
+
+ const infohash = hash(str)
const dbInfohashes = await sqlCommand.getPlaylistInfohash(hls.id)
expect(dbInfohashes).to.include(infohash)
+
+ await checkTrackerInfohash(video.account.host, infohash)
}
}
@@ -298,40 +307,33 @@ export async function completeCheckHlsPlaylist (options: {
const masterPlaylist = await server.streamingPlaylists.get({ url: hlsPlaylist.playlistUrl, token })
- let i = 0
for (const resolution of hlsResolutions) {
expect(masterPlaylist).to.contain(`${resolution}.m3u8`)
expect(masterPlaylist).to.contain(`${resolution}.m3u8`)
-
- const url = 'http://' + videoDetails.account.host
- await hlsInfohashExist(url, hlsPlaylist.playlistUrl, i)
-
- i++
}
}
// Check resolution playlists
- {
- for (const resolution of hlsResolutions) {
- const file = hlsFiles.find(f => f.resolution.id === resolution)
- const playlistName = removeFragmentedMP4Ext(basename(file.fileUrl)) + '.m3u8'
+ for (const resolution of hlsResolutions) {
+ const file = hlsFiles.find(f => f.resolution.id === resolution)
+ const playlistName = removeFragmentedMP4Ext(basename(file.fileUrl)) + '.m3u8'
- let url: string
- if (objectStorageBaseUrl && requiresAuth) {
- url = `${baseUrl}/object-storage-proxy/streaming-playlists/hls/${privatePath}${videoUUID}/${playlistName}`
- } else if (objectStorageBaseUrl) {
- url = `${objectStorageBaseUrl}hls/${videoUUID}/${playlistName}`
- } else {
- url = `${baseUrl}/static/streaming-playlists/hls/${privatePath}${videoUUID}/${playlistName}`
- }
+ let url: string
+ if (objectStorageBaseUrl && requiresAuth) {
+ url = `${baseUrl}/object-storage-proxy/streaming-playlists/hls/${privatePath}${videoUUID}/${playlistName}`
+ } else if (objectStorageBaseUrl) {
+ url = `${objectStorageBaseUrl}hls/${videoUUID}/${playlistName}`
+ } else {
+ url = `${baseUrl}/static/streaming-playlists/hls/${privatePath}${videoUUID}/${playlistName}`
+ }
- const subPlaylist = await server.streamingPlaylists.get({ url, token })
+ const subPlaylist = await server.streamingPlaylists.get({ url, token })
- expect(subPlaylist).to.match(new RegExp(`${uuidRegex}-${resolution}-fragmented.mp4`))
- expect(subPlaylist).to.contain(basename(file.fileUrl))
- }
+ expect(subPlaylist).to.match(new RegExp(`${uuidRegex}-${resolution}-fragmented.mp4`))
+ expect(subPlaylist).to.contain(basename(file.fileUrl))
}
+ // Segment hash
{
let baseUrlAndPath: string
if (objectStorageBaseUrl && requiresAuth) {
@@ -353,6 +355,14 @@ export async function completeCheckHlsPlaylist (options: {
})
}
}
+
+ // Info hashed
+ if (isOrigin) {
+ const sqlCommand = new SQLCommand(server)
+
+ await checkPlaylistInfohash({ video: videoDetails, sqlCommand, files: hlsFiles })
+ await sqlCommand.cleanup()
+ }
}
}
diff --git a/packages/tests/src/shared/tracker.ts b/packages/tests/src/shared/tracker.ts
index 6ab43045623..30352fac87f 100644
--- a/packages/tests/src/shared/tracker.ts
+++ b/packages/tests/src/shared/tracker.ts
@@ -1,14 +1,11 @@
-import { expect } from 'chai'
-import { sha1 } from '@peertube/peertube-node-utils'
import { makeGetRequest } from '@peertube/peertube-server-commands'
+import { expect } from 'chai'
-async function hlsInfohashExist (serverUrl: string, masterPlaylistUrl: string, fileNumber: number) {
+export async function checkTrackerInfohash (serverUrl: string, infohash: string) {
const path = '/tracker/announce'
- const infohash = sha1(`2${masterPlaylistUrl}+V${fileNumber}`)
-
// From bittorrent-tracker
- const infohashBinary = escape(Buffer.from(infohash, 'hex').toString('binary')).replace(/[@*/+]/g, function (char) {
+ const infohashBinary = escape(Buffer.from(infohash, 'utf-8').toString('binary')).replace(/[@*/+]/g, function (char) {
return '%' + char.charCodeAt(0).toString(16).toUpperCase()
})
@@ -21,7 +18,3 @@ async function hlsInfohashExist (serverUrl: string, masterPlaylistUrl: string, f
expect(res.text).to.not.contain('failure')
}
-
-export {
- hlsInfohashExist
-}
diff --git a/packages/tests/src/shared/videos.ts b/packages/tests/src/shared/videos.ts
index 723e169bd63..6a66962d3b5 100644
--- a/packages/tests/src/shared/videos.ts
+++ b/packages/tests/src/shared/videos.ts
@@ -29,7 +29,7 @@ import { tmpdir } from 'os'
import { basename, join } from 'path'
import { dateIsValid, expectStartWith, testImageGeneratedByFFmpeg } from './checks.js'
import { completeCheckHlsPlaylist } from './streaming-playlists.js'
-import { checkWebTorrentWorks } from './webtorrent.js'
+import { checkWebTorrentWorks } from './p2p.js'
export async function completeWebVideoFilesCheck (options: {
server: PeerTubeServer
diff --git a/scripts/build/client.sh b/scripts/build/client.sh
index 357925e7f6a..41ab8b84769 100755
--- a/scripts/build/client.sh
+++ b/scripts/build/client.sh
@@ -47,9 +47,12 @@ languages=(
["kab"]="kab"
)
-cd client
-rm -rf ./dist
+rm -rf ./client/dist
+
+npm run build:embed
+
+cd client
# Don't build other languages if --light arg is provided
if [ -z ${1+x} ] || ([ "$1" != "--light" ] && [ "$1" != "--analyze-bundle" ]); then
@@ -88,7 +91,5 @@ else
--configuration production --stats-json $additionalParams
fi
-cd ../ && npm run build:embed && cd client/
-
# Copy runtime locales
cp -r "./src/locale" "./dist/locale"
diff --git a/scripts/build/embed.sh b/scripts/build/embed.sh
index 70c5fc4cfc0..6c88f750515 100755
--- a/scripts/build/embed.sh
+++ b/scripts/build/embed.sh
@@ -2,4 +2,6 @@
set -eu
+(cd client/src/standalone/player && npm run build)
+
cd client && ./node_modules/.bin/vite -c ./src/standalone/videos/vite.config.mjs build --mode=production
diff --git a/scripts/client-report.sh b/scripts/client-report.sh
index c41e001503e..5ecb71124e8 100755
--- a/scripts/client-report.sh
+++ b/scripts/client-report.sh
@@ -3,5 +3,6 @@
set -eu
npm run concurrently -- -k \
+ "cd client/src/standalone/player/ && npx vite-bundle-visualizer" \
"cd client/src/standalone/videos/ && npx vite-bundle-visualizer" \
"cd client && npx esbuild-visualizer --metadata ./dist/en-US/stats.json --open"
diff --git a/scripts/dev/client.sh b/scripts/dev/client.sh
index 2f0b367d4bb..854bedec773 100755
--- a/scripts/dev/client.sh
+++ b/scripts/dev/client.sh
@@ -2,21 +2,27 @@
set -eu
+(cd client/src/standalone/player && npm run build)
+
clientConfiguration="hmr"
if [ ! -z ${2+x} ] && [ "$2" = "--ar-locale" ]; then
clientConfiguration="ar-locale"
fi
+embedCommand="cd client/src/standalone/player && npm run dev"
clientCommand="cd client && node --max_old_space_size=4096 node_modules/.bin/ng serve --proxy-config proxy.config.json --hmr --configuration $clientConfiguration --host 0.0.0.0 --port 3000"
serverCommand="NODE_ENV=dev node dist/server"
if [ ! -z ${1+x} ] && [ "$1" = "--skip-server" ]; then
- eval $clientCommand
+ node node_modules/.bin/concurrently -k \
+ "$embedCommand" \
+ "$clientCommand"
else
npm run build:server
node node_modules/.bin/concurrently -k \
+ "$embedCommand" \
"$clientCommand" \
"$serverCommand"
fi
diff --git a/scripts/dev/embed.sh b/scripts/dev/embed.sh
index 845036eff7a..b13db57aa75 100755
--- a/scripts/dev/embed.sh
+++ b/scripts/dev/embed.sh
@@ -3,7 +3,9 @@
set -eu
npm run build:server -- --incremental
+(cd client/src/standalone/player && npm run build)
npm run concurrently -- -k \
+ "cd client/src/standalone/player && npm run dev" \
"cd client && ./node_modules/.bin/vite -c ./src/standalone/videos/vite.config.mjs dev" \
"NODE_ENV=dev npm start"
diff --git a/server/core/controllers/tracker.ts b/server/core/controllers/tracker.ts
index dbcc884d29a..9f137b67acd 100644
--- a/server/core/controllers/tracker.ts
+++ b/server/core/controllers/tracker.ts
@@ -25,11 +25,21 @@ const trackerServer = new TrackerServer({
http: false,
udp: false,
ws: false,
- filter: async function (infoHash, params, cb) {
+ filter: async function (infoHashArg, params, cb) {
if (CONFIG.TRACKER.ENABLED === false) {
return cb(new Error('Tracker is disabled on this instance.'))
}
+ let infoHash: string
+
+ try {
+ infoHash = Buffer.from(infoHashArg, 'hex').toString('binary')
+ } catch (err) {
+ logger.error('Cannot parse infohash in tracker filter', { err })
+
+ return cb(new Error('Invalid infoHash.'))
+ }
+
let ip: string
if (params.type === 'ws') {
@@ -126,8 +136,7 @@ function createWebsocketTrackerServer (app: express.Application) {
// ---------------------------------------------------------------------------
export {
- trackerRouter,
- createWebsocketTrackerServer
+ createWebsocketTrackerServer, trackerRouter
}
// ---------------------------------------------------------------------------
diff --git a/server/core/initializers/constants.ts b/server/core/initializers/constants.ts
index d748a1f1cb8..8c86281d203 100644
--- a/server/core/initializers/constants.ts
+++ b/server/core/initializers/constants.ts
@@ -423,7 +423,7 @@ export const CONSTRAINTS_FIELDS = {
}
},
EXTNAME: [] as string[],
- INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2
+ INFO_HASH: { min: 10, max: 100 },
DURATION: { min: 0 }, // Number
TAGS: { min: 0, max: 5 }, // Number of total tags
TAG: { min: 2, max: 30 }, // Length
@@ -1112,7 +1112,9 @@ export const TRACKER_RATE_LIMITS = {
BLOCK_IP_LIFETIME: parseDurationToMs('3 minutes')
}
-export const P2P_MEDIA_LOADER_PEER_VERSION = 2
+// We use -2 instead of 2 because of historical reason
+// When p2p-media-loader bumps to v3, we'll be able to switch to it
+export const P2P_MEDIA_LOADER_PEER_VERSION = -2
// ---------------------------------------------------------------------------
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 7d6279b81b4..1e23216d07e 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
@@ -167,7 +167,7 @@ export function getStreamingPlaylistAttributesFromObject (video: MVideoId, video
for (const playlistUrlObject of playlistUrls) {
const segmentsSha256UrlObject = playlistUrlObject.tag.find(isAPPlaylistSegmentHashesUrlObject)
- const files: unknown[] = playlistUrlObject.tag.filter(u => isAPVideoUrlObject(u))
+ const files = playlistUrlObject.tag.filter(u => isAPVideoUrlObject(u))
const attribute = {
type: VideoStreamingPlaylistType.HLS,
diff --git a/server/core/lib/hls.ts b/server/core/lib/hls.ts
index 87f503eeadf..7e3cb8b265b 100644
--- a/server/core/lib/hls.ts
+++ b/server/core/lib/hls.ts
@@ -24,18 +24,23 @@ import { VideoPathManager } from './video-path-manager.js'
const lTags = loggerTagsFactory('hls')
export async function updateStreamingPlaylistsInfohashesIfNeeded () {
- const playlistsToUpdate = await VideoStreamingPlaylistModel.listByIncorrectPeerVersion()
+ const playlistsToUpdateIds = await VideoStreamingPlaylistModel.listByIncorrectPeerVersion()
// Use separate SQL queries, because we could have many videos to update
- for (const playlist of playlistsToUpdate) {
- await sequelizeTypescript.transaction(async t => {
- const videoFiles = await VideoFileModel.listByStreamingPlaylist(playlist.id, t)
+ for (const playlistId of playlistsToUpdateIds) {
+ try {
+ await sequelizeTypescript.transaction(async t => {
+ const playlist = await VideoStreamingPlaylistModel.loadWithVideo(playlistId, t)
+ const videoFiles = await VideoFileModel.listByStreamingPlaylist(playlistId, t)
- playlist.assignP2PMediaLoaderInfoHashes(playlist.Video, videoFiles)
- playlist.p2pMediaLoaderPeerVersion = P2P_MEDIA_LOADER_PEER_VERSION
+ playlist.assignP2PMediaLoaderInfoHashes(playlist.Video, videoFiles)
+ playlist.p2pMediaLoaderPeerVersion = P2P_MEDIA_LOADER_PEER_VERSION
- await playlist.save({ transaction: t })
- })
+ await playlist.save({ transaction: t })
+ })
+ } catch (err) {
+ logger.error(`Cannot update streaming playlist infohash of playlist id ${playlistId}`, { err })
+ }
}
}
diff --git a/server/core/lib/live/shared/muxing-session.ts b/server/core/lib/live/shared/muxing-session.ts
index ca6743103de..45d37cf5f93 100644
--- a/server/core/lib/live/shared/muxing-session.ts
+++ b/server/core/lib/live/shared/muxing-session.ts
@@ -227,7 +227,7 @@ class MuxingSession extends EventEmitter {
this.streamingPlaylist.playlistUrl = url
}
- this.streamingPlaylist.assignP2PMediaLoaderInfoHashes(this.videoLive.Video, this.allResolutions)
+ this.streamingPlaylist.assignP2PMediaLoaderInfoHashes(this.videoLive.Video, this.allResolutions.map(r => ({ height: r })))
await this.streamingPlaylist.save()
} catch (err) {
diff --git a/server/core/models/video/video-file.ts b/server/core/models/video/video-file.ts
index 9979078ec5b..2e9ce534fbf 100644
--- a/server/core/models/video/video-file.ts
+++ b/server/core/models/video/video-file.ts
@@ -354,23 +354,17 @@ export class VideoFileModel extends SequelizeModel {
const query = {
include: [
{
- model: VideoModel.unscoped(),
+ model: VideoStreamingPlaylistModel.unscoped(),
required: true,
- include: [
- {
- model: VideoStreamingPlaylistModel.unscoped(),
- required: true,
- where: {
- id: streamingPlaylistId
- }
- }
- ]
+ where: {
+ id: streamingPlaylistId
+ }
}
],
transaction
}
- return VideoFileModel.findAll(query)
+ return VideoFileModel.findAll(query)
}
static getStats () {
diff --git a/server/core/models/video/video-streaming-playlist.ts b/server/core/models/video/video-streaming-playlist.ts
index 0f463969b4c..8742e57900b 100644
--- a/server/core/models/video/video-streaming-playlist.ts
+++ b/server/core/models/video/video-streaming-playlist.ts
@@ -5,7 +5,7 @@ import {
type FileStorageType,
type VideoStreamingPlaylistType_Type
} from '@peertube/peertube-models'
-import { sha1 } from '@peertube/peertube-node-utils'
+import { md5 } from '@peertube/peertube-node-utils'
import { logger } from '@server/helpers/logger.js'
import { CONFIG } from '@server/initializers/config.js'
import { getHLSPrivateFileUrl, getObjectStoragePublicFileUrl } from '@server/lib/object-storage/index.js'
@@ -141,12 +141,21 @@ export class VideoStreamingPlaylistModel extends SequelizeModel btoa(md5(input, 'binary').slice(1))
+
// https://github.com/Novage/p2p-media-loader/blob/master/p2p-media-loader-core/lib/p2p-media-manager.ts#L115
for (let i = 0; i < files.length; i++) {
- hashes.push(sha1(`${P2P_MEDIA_LOADER_PEER_VERSION}${playlistUrl}+V${i}`))
+ hashes.push(hash(`v${version}-${playlistUrl}-main-${i}`))
+ }
+
+ // Audio only stream
+ if (files.some(f => f.height === 0)) {
+ hashes.push(hash(`v${version}-${playlistUrl}-secondary-0`))
}
logger.debug('Assigned P2P Media Loader info hashes', { playlistUrl, hashes })
@@ -154,22 +163,18 @@ export class VideoStreamingPlaylistModel extends SequelizeModel r.id)
}
static loadWithVideoAndFiles (id: number) {
@@ -188,14 +193,15 @@ export class VideoStreamingPlaylistModel extends SequelizeModel(id, options)
}
- static loadWithVideo (id: number) {
+ static loadWithVideo (id: number, transaction?: Transaction) {
const options = {
include: [
{
model: VideoModel.unscoped(),
required: true
}
- ]
+ ],
+ transaction
}
return VideoStreamingPlaylistModel.findByPk(id, options)
@@ -242,7 +248,7 @@ export class VideoStreamingPlaylistModel extends SequelizeModel