-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to limit segment on playlist. #43
Comments
it isn't elegant.. but you could quickly and easily write something yourself to shorten your playlists using a hook function. ex: // hooks.js
module.exports = {
"modify_m3u8_content": function(m3u8_content, m3u8_url) {
// if (!some_conditional_test(m3u8_url)) return m3u8_content
const max_segments = 6
const token = "\nhttp"
const all_segments = m3u8_content.split(token)
return all_segments.shift() + token + all_segments.slice(-1 * max_segments).join(token)
}
} note: i haven't tested this code.. just a quick scribble.. but it looks about right |
actually.. on 2nd thought.. that previous example assumes that the manifest uses absolute URLs. // hooks.js
module.exports = {
"modify_m3u8_content": function(m3u8_content, m3u8_url) {
// if (!some_conditional_test(m3u8_url)) return m3u8_content
const max_segments = 6
const token = "\n#EXTINF:"
const all_segments = m3u8_content.split(token)
return all_segments.shift() + token + all_segments.slice(-1 * max_segments).join(token)
}
} |
unit test: {
const m3u8_url = 'https://docs.aws.amazon.com/mediatailor/latest/ug/manifest-hls-example.html'
const m3u8_content = `#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:7
#EXT-X-MEDIA-SEQUENCE:8779957
#EXTINF:6.006,
index_1_8779957.ts?m=1566416212
#EXTINF:6.006,
index_1_8779958.ts?m=1566416212
#EXTINF:5.372,
index_1_8779959.ts?m=1566416212
#EXT-OATCLS-SCTE35:/DAlAAAAAsvhAP/wFAXwAAAGf+/+AdLfiP4AG3dAAAEBAQAAXytxmQ==
#EXT-X-CUE-OUT:20.020
#EXTINF:0.634,
index_1_8779960.ts?m=1566416212
#EXT-X-CUE-OUT-CONT:ElapsedTime=0.634,Duration=21,SCTE35=/DAlAAAAAsvhAP/wFAXwAAAGf+/+AdLfiP4AG3dAAAEBAQAAXytxmQ==
#EXTINF:6.006,
index_1_8779961.ts?m=1566416212
#EXT-X-CUE-OUT-CONT:ElapsedTime=6.640,Duration=21,SCTE35=/DAlAAAAAsvhAP/wFAXwAAAGf+/+AdLfiP4AG3dAAAEBAQAAXytxmQ==
#EXTINF:6.006,
index_1_8779962.ts?m=1566416212
#EXT-X-CUE-OUT-CONT:ElapsedTime=12.646,Duration=21,SCTE35=/DAlAAAAAsvhAP/wFAXwAAAGf+/+AdLfiP4AG3dAAAEBAQAAXytxmQ==
#EXTINF:6.006,
index_1_8779963.ts?m=1566416212
#EXT-X-CUE-OUT-CONT:ElapsedTime=18.652,Duration=21,SCTE35=/DAlAAAAAsvhAP/wFAXwAAAGf+/+AdLfiP4AG3dAAAEBAQAAXytxmQ==
#EXTINF:1.368,
index_1_8779964.ts?m=1566416212
#EXT-X-CUE-IN
#EXTINF:4.638,
index_1_8779965.ts?m=1566416212
#EXTINF:6.006,
index_1_8779966.ts?m=1566416212
#EXTINF:6.006,
index_1_8779967.ts?m=1566416212
#EXTINF:6.006,
index_1_8779968.ts?m=1566416212`
const modify_m3u8_content = function(m3u8_content, m3u8_url) {
// if (!some_conditional_test(m3u8_url)) return m3u8_content
const max_segments = 6
const token = "\n#EXTINF:"
const all_segments = m3u8_content.split(token)
return all_segments.shift() + token + all_segments.slice(-1 * max_segments).join(token)
}
console.log(
modify_m3u8_content(m3u8_content, m3u8_url)
)
} outputs:
success. |
thanks... |
I don't know if those "#EXT-X-CUE-*" tags could be problematic. // hooks.js
const filter_partial_playlist = function(pp) {
const token = '#EXTINF:'
const all_lines = pp.split(/[\r\n]+/g)
return all_lines
.filter(function(line) {
return (!line || (line[0] !== '#') || line.startsWith(token))
})
.join("\n")
}
const modify_m3u8_content = function(m3u8_content, m3u8_url) {
// if (!some_conditional_test(m3u8_url)) return m3u8_content
const max_segments = 6
const token = "\n#EXTINF:"
const all_segments = m3u8_content.split(token)
return all_segments.shift() + token + filter_partial_playlist( all_segments.slice(-1 * max_segments).join(token) )
}
module.exports = {
modify_m3u8_content
} unit test: {
const m3u8_url = 'https://docs.aws.amazon.com/mediatailor/latest/ug/manifest-hls-example.html'
const m3u8_content = `#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:7
#EXT-X-MEDIA-SEQUENCE:8779957
#EXTINF:6.006,
index_1_8779957.ts?m=1566416212
#EXTINF:6.006,
index_1_8779958.ts?m=1566416212
#EXTINF:5.372,
index_1_8779959.ts?m=1566416212
#EXT-OATCLS-SCTE35:/DAlAAAAAsvhAP/wFAXwAAAGf+/+AdLfiP4AG3dAAAEBAQAAXytxmQ==
#EXT-X-CUE-OUT:20.020
#EXTINF:0.634,
index_1_8779960.ts?m=1566416212
#EXT-X-CUE-OUT-CONT:ElapsedTime=0.634,Duration=21,SCTE35=/DAlAAAAAsvhAP/wFAXwAAAGf+/+AdLfiP4AG3dAAAEBAQAAXytxmQ==
#EXTINF:6.006,
index_1_8779961.ts?m=1566416212
#EXT-X-CUE-OUT-CONT:ElapsedTime=6.640,Duration=21,SCTE35=/DAlAAAAAsvhAP/wFAXwAAAGf+/+AdLfiP4AG3dAAAEBAQAAXytxmQ==
#EXTINF:6.006,
index_1_8779962.ts?m=1566416212
#EXT-X-CUE-OUT-CONT:ElapsedTime=12.646,Duration=21,SCTE35=/DAlAAAAAsvhAP/wFAXwAAAGf+/+AdLfiP4AG3dAAAEBAQAAXytxmQ==
#EXTINF:6.006,
index_1_8779963.ts?m=1566416212
#EXT-X-CUE-OUT-CONT:ElapsedTime=18.652,Duration=21,SCTE35=/DAlAAAAAsvhAP/wFAXwAAAGf+/+AdLfiP4AG3dAAAEBAQAAXytxmQ==
#EXTINF:1.368,
index_1_8779964.ts?m=1566416212
#EXT-X-CUE-IN
#EXTINF:4.638,
index_1_8779965.ts?m=1566416212
#EXTINF:6.006,
index_1_8779966.ts?m=1566416212
#EXTINF:6.006,
index_1_8779967.ts?m=1566416212
#EXTINF:6.006,
index_1_8779968.ts?m=1566416212`
const filter_partial_playlist = function(pp) {
const token = '#EXTINF:'
const all_lines = pp.split(/[\r\n]+/g)
return all_lines
.filter(function(line) {
return (!line || (line[0] !== '#') || line.startsWith(token))
})
.join("\n")
}
const modify_m3u8_content = function(m3u8_content, m3u8_url) {
// if (!some_conditional_test(m3u8_url)) return m3u8_content
const max_segments = 6
const token = "\n#EXTINF:"
const all_segments = m3u8_content.split(token)
return all_segments.shift() + token + filter_partial_playlist( all_segments.slice(-1 * max_segments).join(token) )
}
console.log(
modify_m3u8_content(m3u8_content, m3u8_url)
)
} outputs:
success. |
working perfect on my case. problem is on master playlist multibitrate, no "EXTINF:", but adding EXTINF: in last line. |
you wouldn't want to modify your master playlist.. since it only contains a few links.. to child manifests having alternate bitrates. you could either:
// hooks.js
const filter_partial_playlist = function(pp) {
const token = '#EXTINF:'
const all_lines = pp.split(/[\r\n]+/g)
return all_lines
.filter(function(line) {
return (!line || (line[0] !== '#') || line.startsWith(token))
})
.join("\n")
}
const modify_m3u8_content = function(m3u8_content, m3u8_url) {
// if (!some_conditional_test(m3u8_url)) return m3u8_content
const max_segments = 6
const token = "\n#EXTINF:"
const all_segments = m3u8_content.split(token)
if (all_segments.length === 1) return m3u8_content
return all_segments.shift() + token + filter_partial_playlist( all_segments.slice(-1 * max_segments).join(token) )
}
module.exports = {
modify_m3u8_content
} ..that should do the trick |
I should probably mention that this example hook does not support manifests using rotating encryption keys. It would be easy enough to whitelist the return all_segments.shift() + "\n" + get_last_key(all_segments) + token + filter_partial_playlist( all_segments.slice(-1 * max_segments).join(token) ) |
here is an implementation that does support changing encryption keys: // hooks.js
const modify_m3u8_content = function(m3u8_content, m3u8_url) {
// if (!some_conditional_test(m3u8_url)) return m3u8_content
const max_segments = 6
const token = "\n#EXTINF:"
const all_segments = m3u8_content.split(token)
if (all_segments.length === 1) return m3u8_content
return all_segments.shift() + get_last_encryption_key(all_segments, max_segments) + token + filter_partial_playlist( all_segments.slice(-1 * max_segments).join(token) )
}
const get_last_encryption_key = function(segments, count_exclude) {
if (count_exclude >= segments.length) return ''
const token = /\n(#EXT-X-KEY:.*?)(?:[\r\n]|$)/i
for (let i = (segments.length - count_exclude - 1); i >= 0; i--) {
const match = token.exec(segments[i])
if (match) return ("\n" + match[1])
}
return ''
}
const filter_partial_playlist = function(pp) {
const token_whitelist = /^#(?:EXTINF|EXT-X-KEY):/i
const all_lines = pp.split(/[\r\n]+/g)
return all_lines
.filter(function(line) {
return (!line || (line[0] !== '#') || token_whitelist.test(line))
})
.join("\n")
}
module.exports = {
modify_m3u8_content
} unit test: {
const m3u8_url = 'https://github.com/google/ExoPlayer/issues/3725'
const m3u8_content = `#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:5
#EXT-X-PROGRAM-DATE-TIME:2018-01-18T20:42:59+00:00
#EXT-X-KEY:METHOD=AES-128,URI="https://foo.com/321630/keys/id/2348028",IV=0x66AA04B5A372A3D24D91A44C194BD050
#EXT-X-MEDIA-SEQUENCE:259371
#EXTINF:5.005,
018/20/42/59_405.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://foo.com/321630/keys/id/2348028",IV=0xAD9A75768DADF6684C4A55AF649484F2
#EXTINF:5.005,
018/20/43/04_410.ts
#EXTINF:5.005,
018/20/43/09_415.ts
#EXTINF:5.005,
018/20/43/14_420.ts
#EXTINF:5.005,
018/20/43/19_425.ts
#EXTINF:5.005,
018/20/43/24_430.ts
#EXTINF:5.005,
018/20/43/29_435.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://foo.com/321630/keys/id/2348028",IV=0xC4467EF6216F8E93A2D241FCAD2FC486
#EXTINF:5.005,
018/20/43/34_440.ts
#EXTINF:5.005,
018/20/43/39_445.ts
#EXTINF:5.005,
018/20/43/44_450.ts`
const modify_m3u8_content = function(m3u8_content, m3u8_url) {
// if (!some_conditional_test(m3u8_url)) return m3u8_content
const max_segments = 6
const token = "\n#EXTINF:"
const all_segments = m3u8_content.split(token)
if (all_segments.length === 1) return m3u8_content
return all_segments.shift() + get_last_encryption_key(all_segments, max_segments) + token + filter_partial_playlist( all_segments.slice(-1 * max_segments).join(token) )
}
const get_last_encryption_key = function(segments, count_exclude) {
if (count_exclude >= segments.length) return ''
const token = /\n(#EXT-X-KEY:.*?)(?:[\r\n]|$)/i
for (let i = (segments.length - count_exclude - 1); i >= 0; i--) {
const match = token.exec(segments[i])
if (match) return ("\n" + match[1])
}
return ''
}
const filter_partial_playlist = function(pp) {
const token_whitelist = /^#(?:EXTINF|EXT-X-KEY):/i
const all_lines = pp.split(/[\r\n]+/g)
return all_lines
.filter(function(line) {
return (!line || (line[0] !== '#') || token_whitelist.test(line))
})
.join("\n")
}
console.log(
modify_m3u8_content(m3u8_content, m3u8_url)
)
} outputs:
|
thank you. work perfect. i can easely share hls or iptv with hls-proxy. with vpn split i can bypass geo blocking. |
I wrote a little proxy server that can convert DASH manifests to HLS manifests on-the-fly. |
sometimes live video streaming has 2k segments in the playlist. The advantage is that the video can be rewinded. however the m3u gets very large at around 1MB. I want it to only have 5 or 6 segments, is that possible?
The text was updated successfully, but these errors were encountered: