import * as videojs from 'video.js'
import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo, VideoJSComponentInterface } from '../peertube-videojs-typings'
import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from 'p2p-media-loader-hlsjs'
-import { Events } from 'p2p-media-loader-core'
+import { Events, Segment } from 'p2p-media-loader-core'
import { timeToInt } from '../utils'
// videojs-hlsjs-plugin needs videojs in window
initVideoJsContribHlsJsPlayer(player)
this.startTime = timeToInt(options.startTime)
- console.log(this.startTime)
player.src({
type: options.type,
this.trigger('resolutionChange', { auto: this.hlsjs.autoLevelEnabled, resolutionId: data.height })
})
- this.p2pEngine.on(Events.SegmentError, (segment, err) => {
+ this.p2pEngine.on(Events.SegmentError, (segment: Segment, err) => {
console.error('Segment error.', segment, err)
+
+ this.options.redundancyUrlManager.removeByOriginUrl(segment.url)
})
- this.statsP2PBytes.numPeers = 1 + this.options.redundancyBaseUrls.length
+ this.statsP2PBytes.numPeers = 1 + this.options.redundancyUrlManager.countBaseUrls()
this.runStats()
--- /dev/null
+import { basename, dirname } from 'path'
+
+class RedundancyUrlManager {
+
+ // Remember by what new URL we replaced an origin URL
+ private replacedSegmentUrls: { [originUrl: string]: string } = {}
+
+ constructor (private baseUrls: string[] = []) {
+ // empty
+ }
+
+ removeBySegmentUrl (segmentUrl: string) {
+ console.log('Removing redundancy of segment URL %s.', segmentUrl)
+
+ const baseUrl = dirname(segmentUrl)
+
+ this.baseUrls = this.baseUrls.filter(u => u !== baseUrl && u !== baseUrl + '/')
+ }
+
+ removeByOriginUrl (originUrl: string) {
+ const replaced = this.replacedSegmentUrls[originUrl]
+ if (!replaced) return
+
+ return this.removeBySegmentUrl(replaced)
+ }
+
+ buildUrl (url: string) {
+ delete this.replacedSegmentUrls[url]
+
+ const max = this.baseUrls.length + 1
+ const i = this.getRandomInt(max)
+
+ if (i === max - 1) return url
+
+ const newBaseUrl = this.baseUrls[i]
+ const slashPart = newBaseUrl.endsWith('/') ? '' : '/'
+
+ const newUrl = newBaseUrl + slashPart + basename(url)
+ this.replacedSegmentUrls[url] = newUrl
+
+ return newUrl
+ }
+
+ countBaseUrls () {
+ return this.baseUrls.length
+ }
+
+ private getRandomInt (max: number) {
+ return Math.floor(Math.random() * Math.floor(max))
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+ RedundancyUrlManager
+}
-import { basename } from 'path'
import { Segment } from 'p2p-media-loader-core'
+import { RedundancyUrlManager } from './redundancy-url-manager'
-function segmentUrlBuilderFactory (baseUrls: string[]) {
+function segmentUrlBuilderFactory (redundancyUrlManager: RedundancyUrlManager) {
return function segmentBuilder (segment: Segment) {
- const max = baseUrls.length + 1
- const i = getRandomInt(max)
-
- if (i === max - 1) return segment.url
-
- const newBaseUrl = baseUrls[i]
- const middlePart = newBaseUrl.endsWith('/') ? '' : '/'
-
- return newBaseUrl + middlePart + basename(segment.url)
+ return redundancyUrlManager.buildUrl(segment.url)
}
}
export {
segmentUrlBuilderFactory
}
-
-// ---------------------------------------------------------------------------
-
-function getRandomInt (max: number) {
- return Math.floor(Math.random() * Math.floor(max))
-}
import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n'
import { segmentValidatorFactory } from './p2p-media-loader/segment-validator'
import { segmentUrlBuilderFactory } from './p2p-media-loader/segment-url-builder'
+import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager'
// Change 'Playback Rate' to 'Speed' (smaller for our settings menu)
videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed'
}
if (mode === 'p2p-media-loader') {
+ const redundancyUrlManager = new RedundancyUrlManager(options.p2pMediaLoader.redundancyBaseUrls)
+
const p2pMediaLoader: P2PMediaLoaderPluginOptions = {
- redundancyBaseUrls: options.p2pMediaLoader.redundancyBaseUrls,
+ redundancyUrlManager,
type: 'application/x-mpegURL',
startTime: commonOptions.startTime,
src: p2pMediaLoaderOptions.playlistUrl
segmentValidator: segmentValidatorFactory(options.p2pMediaLoader.segmentsSha256Url),
rtcConfig: getRtcConfig(),
requiredSegmentsPriority: 5,
- segmentUrlBuilder: segmentUrlBuilderFactory(options.p2pMediaLoader.redundancyBaseUrls)
+ segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager)
},
segments: {
swarmId: p2pMediaLoaderOptions.playlistUrl
import { WebTorrentPlugin } from './webtorrent/webtorrent-plugin'
import { P2pMediaLoaderPlugin } from './p2p-media-loader/p2p-media-loader-plugin'
import { PlayerMode } from './peertube-player-manager'
+import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager'
declare namespace videojs {
interface Player {
}
type P2PMediaLoaderPluginOptions = {
- redundancyBaseUrls: string[]
+ redundancyUrlManager: RedundancyUrlManager
type: string
src: string