Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/playback/dash/DASHHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export class DASHHandler extends Transform {
`Selected: id=${selected.id}, codecs=${selected.codecs}, bandwidth=${selected.bandwidth}`
)

const initRes = await makeRequest(selected.initUrl, {
const initRes = await makeRequest(this._resolveUrl(selected.initUrl), {
headers: this.options.headers,
method: 'GET',
localAddress: this.options.localAddress,
Expand Down Expand Up @@ -295,11 +295,24 @@ export class DASHHandler extends Transform {
let segNum = selected.startNumber
for (const segGroup of selected.segments) {
for (let r = 0; r <= segGroup.repeat; r++) {
yield selected.mediaTemplate.replace('$Number$', String(segNum++))
yield this._resolveUrl(
selected.mediaTemplate.replace('$Number$', String(segNum++))
)
}
}
}

/**
* Resolves a potentially relative URL against the MPD location.
*/
private _resolveUrl(url: string): string {
try {
return new URL(url, this.mpdUrl).href
} catch {
return url
}
}

private _countSegments(selected: DASHRepresentation): number {
let count = 0
for (const segGroup of selected.segments) {
Expand Down
4 changes: 2 additions & 2 deletions src/playback/demuxers/WebmOpus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,8 @@ abstract class WebmBaseDemuxer extends Transform {
const skipped = this.ringBuffer.length
if (skipped > 0) webmOpusProfiler.skippedBytes += skipped
this.skipUntil = res._skipUntil
this.ringBuffer.skip(this.ringBuffer.length)
this.processed += BigInt(this.ringBuffer.length)
this.ringBuffer.skip(skipped)
this.processed += BigInt(skipped)
break
}

Expand Down
11 changes: 11 additions & 0 deletions src/playback/hls/HLSHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,17 @@ export default class HLSHandler extends PassThrough {
})
}

if (
!this.isLive &&
this.segmentQueue.length === 0 &&
!this.isFetching &&
!this.stop &&
!this.destroyed
) {
this.end()
return
}

if (this.isLive && !playlistContent.includes('#EXT-X-ENDLIST')) {
this._scheduleNextTick(parsed.targetDuration)
}
Expand Down
16 changes: 10 additions & 6 deletions src/playback/processing/CrossfadeController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ interface ReverbTailState {
allpassLeft: Float32Array
allpassRight: Float32Array
posComb1: number
posComb1Right: number
posComb2: number
posComb2Right: number
posAllpass: number
}

Expand All @@ -102,7 +104,9 @@ function createReverbTailState(): ReverbTailState {
allpassLeft: new Float32Array(556),
allpassRight: new Float32Array(556),
posComb1: 0,
posComb1Right: 0,
posComb2: 0,
posComb2Right: 0,
posAllpass: 0
}
}
Expand Down Expand Up @@ -1007,17 +1011,17 @@ export class CrossfadeController extends Transform {

const c1L = rev.comb1Left[rev.posComb1] ?? 0
rev.comb1Left[rev.posComb1] = inputLeft + c1L * feedback
const c1R = rev.comb1Right[rev.posComb1 % rev.comb1Right.length] ?? 0
rev.comb1Right[rev.posComb1 % rev.comb1Right.length] =
inputRight + c1R * feedback
const c1R = rev.comb1Right[rev.posComb1Right] ?? 0
rev.comb1Right[rev.posComb1Right] = inputRight + c1R * feedback
rev.posComb1 = (rev.posComb1 + 1) % rev.comb1Left.length
rev.posComb1Right = (rev.posComb1Right + 1) % rev.comb1Right.length

const c2L = rev.comb2Left[rev.posComb2] ?? 0
rev.comb2Left[rev.posComb2] = inputLeft + c2L * feedback
const c2R = rev.comb2Right[rev.posComb2 % rev.comb2Right.length] ?? 0
rev.comb2Right[rev.posComb2 % rev.comb2Right.length] =
inputRight + c2R * feedback
const c2R = rev.comb2Right[rev.posComb2Right] ?? 0
rev.comb2Right[rev.posComb2Right] = inputRight + c2R * feedback
rev.posComb2 = (rev.posComb2 + 1) % rev.comb2Left.length
rev.posComb2Right = (rev.posComb2Right + 1) % rev.comb2Right.length

const combMixL = (c1L + c2L) * 0.5
const combMixR = (c1R + c2R) * 0.5
Expand Down
4 changes: 0 additions & 4 deletions src/playback/processing/streamProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1632,10 +1632,6 @@ class AACDecoderStream extends Transform {
const frameInfo = this._findADTSFrame()
if (!frameInfo) break

if (frameInfo.start > 0) {
this.ringBuffer.skip(frameInfo.start)
}

const adtsFrame = frameInfo.frame

if (!this.isConfigured) {
Expand Down
7 changes: 5 additions & 2 deletions src/sources/gaana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ const USER_AGENT =
const API_URL = 'https://gaana.com/apiv2'
const STREAM_URL_API = 'https://gaana.com/api/stream-url'
const CRYPTO_KEY = Buffer.from('gy1t#b@jl(b$wtme', 'utf8')
const CRYPTO_IV = Buffer.from('xC4dmVJAq14BfntX', 'utf8')
const HLS_BASE_URL = 'https://vodhlsgaana-ebw.akamaized.net/'

/**
Expand Down Expand Up @@ -826,9 +825,13 @@ export default class GaanaSource {
const offset = Number.parseInt(encryptedData[0] || '', 10)
if (Number.isNaN(offset)) return ''

const iv = Buffer.from(
encryptedData.substring(offset, offset + 16),
'utf8'
)
const ciphertextB64 = encryptedData.substring(offset + 16)
const ciphertext = Buffer.from(`${ciphertextB64}==`, 'base64')
const decipher = createDecipheriv('aes-128-cbc', CRYPTO_KEY, CRYPTO_IV)
const decipher = createDecipheriv('aes-128-cbc', CRYPTO_KEY, iv)
decipher.setAutoPadding(false)

let decrypted = decipher.update(ciphertext)
Expand Down
22 changes: 16 additions & 6 deletions src/sources/nicovideo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,21 +520,31 @@ export default class NicoVideoSource {
}

/**
* Converts the limited NicoVideo duration string into milliseconds.
* Converts a NicoVideo ISO-8601 duration string into milliseconds.
*
* This preserves the source's current behavior, which only reads the final
* seconds segment from NicoVideo's duration string.
* Handles all duration components (hours, minutes and seconds), e.g. a
* "PT4M05S" string correctly resolves to 245000 ms instead of only the
* trailing seconds value.
*
* @param duration - NicoVideo ISO-8601 duration string.
* @returns Duration in milliseconds based on the parsed seconds component.
* @returns Duration in milliseconds.
*/
private parseDurationMillis(duration?: string): number {
if (!duration) {
return 0
}

const seconds = duration.match(/(\d+)S/)?.[1]
return Number.parseInt(seconds ?? '0', 10) * 1000
const match = duration.match(
/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?/
)
if (!match) {
return 0
}

const hours = Number.parseInt(match[1] ?? '0', 10)
const minutes = Number.parseInt(match[2] ?? '0', 10)
const seconds = Number.parseFloat(match[3] ?? '0')
return Math.round((hours * 3600 + minutes * 60 + seconds) * 1000)
}

/**
Expand Down
Loading