diff --git a/client/package.json b/client/package.json index 30cb3a188..c93af4aa7 100644 --- a/client/package.json +++ b/client/package.json @@ -48,6 +48,8 @@ "@ngx-loading-bar/core": "^5.0.0", "@ngx-loading-bar/http-client": "^5.0.0", "@ngx-loading-bar/router": "^5.0.0", + "@peertube/p2p-media-loader-core": "^1.0.2", + "@peertube/p2p-media-loader-hlsjs": "^1.0.4", "@types/chart.js": "^2.9.16", "@types/core-js": "^2.5.2", "@types/debug": "^4.1.5", @@ -76,7 +78,7 @@ "dexie": "^3.0.0", "file-loader": "^6.0.0", "focus-visible": "^5.0.2", - "hls.js": "^0.14.16", + "hls.js": "^1.0.7", "html-loader": "^2.1.2", "html-webpack-plugin": "^5.3.1", "https-browserify": "^1.0.0", @@ -93,7 +95,6 @@ "markdown-it": "12.0.6", "mini-css-extract-plugin": "^1.6.0", "ngx-uploadx": "^4.1.0", - "p2p-media-loader-hlsjs": "^0.6.2", "path-browserify": "^1.0.0", "primeng": "^12.0.0-rc.1", "process": "^0.11.10", diff --git a/client/src/assets/player/p2p-media-loader/hls-plugin.ts b/client/src/assets/player/p2p-media-loader/hls-plugin.ts index 53969a5a5..3050110cd 100644 --- a/client/src/assets/player/p2p-media-loader/hls-plugin.ts +++ b/client/src/assets/player/p2p-media-loader/hls-plugin.ts @@ -264,20 +264,16 @@ class Html5Hlsjs { if (this.errorCounts[ data.type ]) this.errorCounts[ data.type ] += 1 else this.errorCounts[ data.type ] = 1 - if (!data.fatal) { - console.warn(error.message) - return - } - - console.error(error.message) + if (data.fatal) console.warn(error.message) + else console.error(error.message, data) if (data.type === Hlsjs.ErrorTypes.NETWORK_ERROR) { error.code = 2 this._handleNetworkError(error) - } else if (data.type === Hlsjs.ErrorTypes.MEDIA_ERROR && data.details !== 'manifestIncompatibleCodecsError') { + } else if (data.fatal && data.type === Hlsjs.ErrorTypes.MEDIA_ERROR && data.details !== 'manifestIncompatibleCodecsError') { error.code = 3 this._handleMediaError(error) - } else { + } else if (data.fatal) { this.hls.destroy() console.info('bubbling error up to VIDEOJS') this.tech.error = () => error as any @@ -286,12 +282,12 @@ class Html5Hlsjs { } private switchQuality (qualityId: number) { - this.hls.nextLevel = qualityId + this.hls.currentLevel = qualityId } private _levelLabel (level: Hlsjs.Level) { if (this.player.srOptions_.levelLabelHandler) { - return this.player.srOptions_.levelLabelHandler(level) + return this.player.srOptions_.levelLabelHandler(level as any) } if (level.height) return level.height + 'p' diff --git a/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts b/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts index 2eb849d2b..093795e48 100644 --- a/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts +++ b/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts @@ -1,7 +1,7 @@ import * as Hlsjs from 'hls.js/dist/hls.light.js' -import { Events, Segment } from 'p2p-media-loader-core' -import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from 'p2p-media-loader-hlsjs' import videojs from 'video.js' +import { Events, Segment } from '@peertube/p2p-media-loader-core' +import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from '@peertube/p2p-media-loader-hlsjs' import { timeToInt } from '@shared/core-utils' import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo } from '../peertube-videojs-typings' import { registerConfigPlugin, registerSourceHandler } from './hls-plugin' @@ -36,9 +36,6 @@ class P2pMediaLoaderPlugin extends Plugin { private networkInfoInterval: any - private hlsjsCurrentLevel: number - private hlsjsLevels: Hlsjs.Level[] - constructor (player: videojs.Player, options?: P2PMediaLoaderPluginOptions) { super(player) @@ -88,13 +85,12 @@ class P2pMediaLoaderPlugin extends Plugin { } getCurrentLevel () { - return this.hlsjsLevels.find(l => l.level === this.hlsjsCurrentLevel) + return this.hlsjs.levels[this.hlsjs.currentLevel] } getLiveLatency () { - return undefined as number - // FIXME: Use latency when hls >= V1 - // return this.hlsjs.latency + // FIXME: typings + return Math.round((this.hlsjs as any).latency) } getHLSJS () { @@ -140,31 +136,23 @@ class P2pMediaLoaderPlugin extends Plugin { } private runStats () { - this.p2pEngine.on(Events.PieceBytesDownloaded, (method: string, size: number) => { + this.p2pEngine.on(Events.PieceBytesDownloaded, (method: string, _segment, bytes: number) => { const elem = method === 'p2p' ? this.statsP2PBytes : this.statsHTTPBytes - elem.pendingDownload.push(size) - elem.totalDownload += size + elem.pendingDownload.push(bytes) + elem.totalDownload += bytes }) - this.p2pEngine.on(Events.PieceBytesUploaded, (method: string, size: number) => { + this.p2pEngine.on(Events.PieceBytesUploaded, (method: string, _segment, bytes: number) => { const elem = method === 'p2p' ? this.statsP2PBytes : this.statsHTTPBytes - elem.pendingUpload.push(size) - elem.totalUpload += size + elem.pendingUpload.push(bytes) + elem.totalUpload += bytes }) this.p2pEngine.on(Events.PeerConnect, () => this.statsP2PBytes.numPeers++) this.p2pEngine.on(Events.PeerClose, () => this.statsP2PBytes.numPeers--) - this.hlsjs.on(Hlsjs.Events.MANIFEST_PARSED, (_e, manifest) => { - this.hlsjsCurrentLevel = manifest.firstLevel - this.hlsjsLevels = manifest.levels - }) - this.hlsjs.on(Hlsjs.Events.LEVEL_LOADED, (_e, level) => { - this.hlsjsCurrentLevel = level.levelId || (level as any).id - }) - this.networkInfoInterval = setInterval(() => { const p2pDownloadSpeed = this.arraySum(this.statsP2PBytes.pendingDownload) const p2pUploadSpeed = this.arraySum(this.statsP2PBytes.pendingUpload) diff --git a/client/src/assets/player/p2p-media-loader/segment-url-builder.ts b/client/src/assets/player/p2p-media-loader/segment-url-builder.ts index 039777cea..ad0e460ae 100644 --- a/client/src/assets/player/p2p-media-loader/segment-url-builder.ts +++ b/client/src/assets/player/p2p-media-loader/segment-url-builder.ts @@ -1,4 +1,4 @@ -import { Segment } from 'p2p-media-loader-core' +import { Segment } from '@peertube/p2p-media-loader-core' import { RedundancyUrlManager } from './redundancy-url-manager' function segmentUrlBuilderFactory (redundancyUrlManager: RedundancyUrlManager) { diff --git a/client/src/assets/player/p2p-media-loader/segment-validator.ts b/client/src/assets/player/p2p-media-loader/segment-validator.ts index 4a0caec5e..a28474793 100644 --- a/client/src/assets/player/p2p-media-loader/segment-validator.ts +++ b/client/src/assets/player/p2p-media-loader/segment-validator.ts @@ -1,5 +1,5 @@ import { wait } from '@root-helpers/utils' -import { Segment } from 'p2p-media-loader-core' +import { Segment } from '@peertube/p2p-media-loader-core' import { basename } from 'path' type SegmentsJSON = { [filename: string]: string | { [byterange: string]: string } } diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 766ad203e..c45e8f53e 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts @@ -22,6 +22,7 @@ import './videojs-components/settings-panel-child' import './videojs-components/theater-button' import './playlist/playlist-plugin' import videojs from 'video.js' +import { HlsJsEngineSettings } from '@peertube/p2p-media-loader-hlsjs' import { PluginsManager } from '@root-helpers/plugins-manager' import { buildVideoLink, decorateVideoLink } from '@shared/core-utils' import { isDefaultLocale } from '@shared/core-utils/i18n' @@ -30,11 +31,12 @@ import { copyToClipboard } from '../../root-helpers/utils' import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager' import { segmentUrlBuilderFactory } from './p2p-media-loader/segment-url-builder' import { segmentValidatorFactory } from './p2p-media-loader/segment-validator' -import { getStoredP2PEnabled } from './peertube-player-local-storage' +import { getAverageBandwidthInStore, getStoredP2PEnabled, saveAverageBandwidth } from './peertube-player-local-storage' import { NextPreviousVideoButtonOptions, P2PMediaLoaderPluginOptions, PeerTubeLinkButtonOptions, + PlayerNetworkInfo, PlaylistPluginOptions, UserWatching, VideoJSCaption, @@ -148,7 +150,7 @@ export class PeertubePlayerManager { if (mode === 'webtorrent') await import('./webtorrent/webtorrent-plugin') if (mode === 'p2p-media-loader') { [ p2pMediaLoader ] = await Promise.all([ - import('p2p-media-loader-hlsjs'), + import('@peertube/p2p-media-loader-hlsjs'), import('./p2p-media-loader/p2p-media-loader-plugin') ]) } @@ -193,6 +195,12 @@ export class PeertubePlayerManager { mode }) + player.on('p2pInfo', (_, data: PlayerNetworkInfo) => { + if (data.source !== 'p2p-media-loader' || isNaN(data.bandwidthEstimate)) return + + saveAverageBandwidth(data.bandwidthEstimate) + }) + return res(player) }) }) @@ -359,12 +367,13 @@ export class PeertubePlayerManager { consumeOnly = true } - const p2pMediaLoaderConfig = { + const p2pMediaLoaderConfig: HlsJsEngineSettings = { loader: { trackerAnnounce, segmentValidator: segmentValidatorFactory(options.p2pMediaLoader.segmentsSha256Url, options.common.isLive), rtcConfig: getRtcConfig(), requiredSegmentsPriority: 1, + simultaneousHttpDownloads: 1, segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager), useP2P: getStoredP2PEnabled(), consumeOnly @@ -373,6 +382,7 @@ export class PeertubePlayerManager { swarmId: p2pMediaLoaderOptions.playlistUrl } } + const hlsjs = { levelLabelHandler: (level: { height: number, width: number }) => { const resolution = Math.min(level.height || 0, level.width || 0) @@ -387,12 +397,7 @@ export class PeertubePlayerManager { return label }, html5: { - hlsjsConfig: { - capLevelToPlayerSize: true, - autoStartLoad: false, - liveSyncDurationCount: 5, - loader: new p2pMediaLoaderModule.Engine(p2pMediaLoaderConfig).createLoaderClass() - } + hlsjsConfig: this.getHLSOptions(p2pMediaLoaderModule, p2pMediaLoaderConfig) } } @@ -402,6 +407,28 @@ export class PeertubePlayerManager { return toAssign } + private static getHLSOptions (p2pMediaLoaderModule: any, p2pMediaLoaderConfig: HlsJsEngineSettings) { + const base = { + capLevelToPlayerSize: true, + autoStartLoad: false, + liveSyncDurationCount: 5, + + loader: new p2pMediaLoaderModule.Engine(p2pMediaLoaderConfig).createLoaderClass() + } + + const averageBandwidth = getAverageBandwidthInStore() + if (!averageBandwidth) return base + + return { + ...base, + + abrEwmaDefaultEstimate: averageBandwidth * 8, // We want bit/s + startLevel: -1, + testBandwidth: false, + debug: false + } + } + private static addWebTorrentOptions (plugins: VideoJSPluginOptions, options: PeertubePlayerManagerOptions) { const commonOptions = options.common const webtorrentOptions = options.webtorrent diff --git a/client/src/assets/player/peertube-plugin.ts b/client/src/assets/player/peertube-plugin.ts index 919b7c239..ade8e2ee4 100644 --- a/client/src/assets/player/peertube-plugin.ts +++ b/client/src/assets/player/peertube-plugin.ts @@ -228,6 +228,7 @@ class PeerTubePlugin extends Plugin { } } + console.log('Resolution changed.', data) this.trigger('resolutionChange', data) } diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts index d3c75990b..f0eb129d4 100644 --- a/client/src/assets/player/peertube-videojs-typings.ts +++ b/client/src/assets/player/peertube-videojs-typings.ts @@ -1,4 +1,4 @@ -import { Config, Level } from 'hls.js' +import { HlsConfig, Level } from 'hls.js' import videojs from 'video.js' import { VideoFile, VideoPlaylist, VideoPlaylistElement } from '@shared/models' import { P2pMediaLoaderPlugin } from './p2p-media-loader/p2p-media-loader-plugin' @@ -60,7 +60,7 @@ export interface VideoJSTechHLS extends videojs.Tech { } export interface HlsjsConfigHandlerOptions { - hlsjsConfig?: Config & { cueHandler: any }// FIXME: typings + hlsjsConfig?: HlsConfig & { cueHandler: any }// FIXME: typings captionConfig?: any // FIXME: typings levelLabelHandler?: (level: Level) => string diff --git a/client/yarn.lock b/client/yarn.lock index 9242cd219..44166a868 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -1333,6 +1333,26 @@ node-gyp "^7.1.0" read-package-json-fast "^2.0.1" +"@peertube/p2p-media-loader-core@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@peertube/p2p-media-loader-core/-/p2p-media-loader-core-1.0.2.tgz#ef36a23df5a5393cc5d180a45dfb70d2c3ecff87" + integrity sha512-2F6Cx2ncXe+ySaaGiAWf7jJ8snJpyd7WNCxYbJ5Zadst1mNSQlxUqH4/qEl/bai4DiuzzhudlzXS8U3SX9c9Jw== + dependencies: + bittorrent-tracker "^9.16.1" + debug "^4.3.1" + events "^3.3.0" + sha.js "^2.4.11" + simple-peer "^9.10.0" + +"@peertube/p2p-media-loader-hlsjs@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@peertube/p2p-media-loader-hlsjs/-/p2p-media-loader-hlsjs-1.0.4.tgz#849809067886e41bf2ba7e71a2da33478863bc66" + integrity sha512-FFFlYPFwTGxB3CPChqlzPqJw65ajIjCCxCn4IQRNuagYpo0fdaxrgepMHNPW3Zl5DmvEppv+ohUfYyr98U1wiw== + dependencies: + "@peertube/p2p-media-loader-core" "^1.0.2" + events "^3.3.0" + m3u8-parser "^4.6.0" + "@polka/url@^1.0.0-next.15": version "1.0.0-next.15" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.15.tgz#6a9d143f7f4f49db2d782f9e1c8839a29b43ae23" @@ -2445,7 +2465,7 @@ bittorrent-protocol@^3.2.0: speedometer "^1.1.0" unordered-array-remove "^1.0.2" -bittorrent-tracker@^9.0.0, bittorrent-tracker@^9.14.4: +bittorrent-tracker@^9.0.0: version "9.17.2" resolved "https://registry.yarnpkg.com/bittorrent-tracker/-/bittorrent-tracker-9.17.2.tgz#1afb02d3d2fb474c13389c45e8a2b6919bff40bd" integrity sha512-hXjed0OnB16da+ScJUZnrAZbf9gMgSLKqh5rJebtYnTRgN4o1mX0DOPH3Nf5RFCs935ibhSmZN5nwbkh+3MdEA== @@ -2475,6 +2495,36 @@ bittorrent-tracker@^9.0.0, bittorrent-tracker@^9.14.4: bufferutil "^4.0.3" utf-8-validate "^5.0.5" +bittorrent-tracker@^9.16.1: + version "9.17.4" + resolved "https://registry.yarnpkg.com/bittorrent-tracker/-/bittorrent-tracker-9.17.4.tgz#663f51064a924e945cb6ca19a0c293aca258128b" + integrity sha512-ykhdVQHtLfn4DYSJUQD/zFAbP8YwnF6nGlj2SBnCY4xkW5bhwXPeFZUhryAtdITl0qNL/FpmFOamBZfxIwkbxg== + dependencies: + bencode "^2.0.1" + bittorrent-peerid "^1.3.3" + bn.js "^5.2.0" + chrome-dgram "^3.0.6" + compact2string "^1.4.1" + debug "^4.1.1" + ip "^1.1.5" + lru "^3.1.0" + minimist "^1.2.5" + once "^1.4.0" + queue-microtask "^1.2.3" + random-iterate "^1.0.1" + randombytes "^2.1.0" + run-parallel "^1.2.0" + run-series "^1.1.9" + simple-get "^4.0.0" + simple-peer "^9.11.0" + simple-websocket "^9.1.0" + string2compact "^1.3.0" + unordered-array-remove "^1.0.2" + ws "^7.4.5" + optionalDependencies: + bufferutil "^4.0.3" + utf-8-validate "^5.0.5" + bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -4179,12 +4229,12 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -eventemitter3@^4.0.0, eventemitter3@^4.0.3: +eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -events@^3.0.0, events@^3.2.0: +events@^3.2.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -4642,7 +4692,7 @@ gensync@^1.0.0-beta.1, 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.0.2, get-browser-rtc@^1.1.0: +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== @@ -4930,13 +4980,10 @@ hex-color-regex@^1.1.0: resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== -hls.js@^0.14.16: - version "0.14.17" - resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.14.17.tgz#0127cff2ec2f994a54eb955fe669ef6153a8e317" - integrity sha512-25A7+m6qqp6UVkuzUQ//VVh2EEOPYlOBg32ypr34bcPO7liBMOkKFvbjbCBfiPAOTA/7BSx1Dujft3Th57WyFg== - dependencies: - eventemitter3 "^4.0.3" - url-toolkit "^2.1.6" +hls.js@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-1.0.7.tgz#b4ab75e7a46650d02245a1da091efd15f07d16eb" + integrity sha512-NsGaksvOuYNyTmu/w239EtYFMadFzIoDkmStc1FDRcrGmvxOfMGKad/hLj4NHoE8H1S+Q8dT7HufMJJ6yiht7g== hosted-git-info@^2.1.4: version "2.8.9" @@ -6341,7 +6388,7 @@ lru@^3.1.0: dependencies: inherits "^2.0.1" -m3u8-parser@4.7.0, m3u8-parser@^4.4.0: +m3u8-parser@4.7.0, m3u8-parser@^4.6.0: version "4.7.0" resolved "https://registry.yarnpkg.com/m3u8-parser/-/m3u8-parser-4.7.0.tgz#e01e8ce136098ade1b14ee691ea20fc4dc60abf6" integrity sha512-48l/OwRyjBm+QhNNigEEcRcgbRvnUjL7rxs597HmW9QSNbyNvt+RcZ9T/d9vxi9A9z7EZrB1POtZYhdRlwYQkQ== @@ -7374,27 +7421,6 @@ 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@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/p2p-media-loader-core/-/p2p-media-loader-core-0.6.2.tgz#7e46cf8fc4357596f389e106bee850908cc974ef" - integrity sha512-yspgCOrVVYitVNece5CA6W/kcVA0UybvbD4kyBE5ooyhCAXQK5/q6JsIpXiVQ3VkQw8Qs4mfZjU39Vt6vEk6aw== - dependencies: - bittorrent-tracker "^9.14.4" - debug "^4.1.1" - events "^3.0.0" - get-browser-rtc "^1.0.2" - sha.js "^2.4.11" - simple-peer "^9.5.0" - -p2p-media-loader-hlsjs@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/p2p-media-loader-hlsjs/-/p2p-media-loader-hlsjs-0.6.2.tgz#b66f977a5d28986c8f6e62d2ffa297aec3c05186" - integrity sha512-5LgqWPDsgyST9rxoHGDpExZU1rIDZIT0qft2wAnlg8Cb8aVeaBxUsmF4Sj692Qb5/GBDsi8vLE03LW8gpvlh1g== - dependencies: - events "^3.0.0" - m3u8-parser "^4.4.0" - p2p-media-loader-core "^0.6.2" - package-json-versionify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/package-json-versionify/-/package-json-versionify-1.0.4.tgz#5860587a944873a6b7e6d26e8e51ffb22315bf17" @@ -9313,7 +9339,7 @@ simple-get@^4.0.0: once "^1.3.1" simple-concat "^1.0.0" -simple-peer@^9.11.0, simple-peer@^9.5.0, simple-peer@^9.9.3: +simple-peer@^9.10.0, simple-peer@^9.11.0, simple-peer@^9.9.3: version "9.11.0" resolved "https://registry.yarnpkg.com/simple-peer/-/simple-peer-9.11.0.tgz#e8d27609c7a610c3ddd75767da868e8daab67571" integrity sha512-qvdNu/dGMHBm2uQ7oLhQBMhYlrOZC1ywXNCH/i8I4etxR1vrjCnU6ZSQBptndB1gcakjo2+w4OHo7Sjza1SHxg== @@ -10538,7 +10564,7 @@ url-parse@^1.4.3, url-parse@^1.5.1: querystringify "^2.1.1" requires-port "^1.0.0" -url-toolkit@^2.1.6, url-toolkit@^2.2.1: +url-toolkit@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/url-toolkit/-/url-toolkit-2.2.2.tgz#51ef27b56d3187185f9ecf4a8ac7e8f55203c89d" integrity sha512-l25w6Sy+Iy3/IbogunxhWwljPaDnqpiKvrQRoLBm6DfISco7NyRIS7Zf6+Oxhy1T8kHxWdwLND7ZZba6NjXMug==