-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplayer.js
113 lines (106 loc) · 3.9 KB
/
player.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
const STREAM_URL = "./stream_url.txt";
const TOKEN_LIFETIME = 20000;
const withToken = url => `${url}?token=${Date.now()}`;
const getPlaylistUrl = () => {
return fetch(STREAM_URL)
.then(response => response.text())
.then(url => {
return withToken(url);
})
.catch(err => {
reject(`Error to get new token from ${STREAM_URL}`)
})
}
const getNewToken = () => {
// write your own fetch() chain which returns new token.
const newToken = Date.now();
return Promise.resolve(newToken);
}
const replaceParam = (url, param, newValue) => {
const urlObj = new URL(url);
urlObj.searchParams.set(param, newValue)
return urlObj.toString();
}
const getParam = (url, param) => {
const urlObj = new URL(url);
return urlObj.searchParams.get(param)
}
const pLoaderAutoRefresh = refreshInterval => {
// let lastRefreshTimestamp = Date.now();
let lastRefreshTimestamp = 0;
let lastUrl = '';
return function(config) {
const loader = new Hls.DefaultConfig.loader(config);
this.abort = () => loader.abort();
this.destroy = () => loader.destroy();
this.load = async (context, config, callbacks) => {
let { type, url } = context;
// if play-list request, send original request and return
if(type === 'manifest') {
loader.load(context, config, callbacks);
return;
}
// then type is 'level' (type when requesting chunk-list)
const msRefreshElsapsed = Date.now() - lastRefreshTimestamp;
const IS_FIRST_REQUEST = lastRefreshTimestamp === 0;
if(msRefreshElsapsed > refreshInterval || IS_FIRST_REQUEST){
// if time elapsed given refresh interval, request new token and replace it with old token.
try {
const newToken = await getNewToken();
context.url = replaceParam(context.url, 'token', newToken);
loader.load(context, config, callbacks);
lastRefreshTimestamp = Date.now();
lastUrl = context.url;
} catch (err) {
// request original request
loader.load(context, config, callbacks);
}
} else {
context.url = lastUrl !== '' ? lastUrl : context.url;
loader.load(context, config, callbacks);
}
};
}
}
// main
const video = document.getElementById('video');
const message = document.getElementById('message');
const container = document.getElementById('container');
const tokenHistory = document.getElementById('tokenHistory');
const writeMessage = msg => {
if(message.innerText === msg) return;
message.style.fontWeight = 'bold';
message.style.fontSize = '12px';
message.innerText = msg;
setTimeout(() => {
message.style.fontWeight = 'normal';
message.style.fontSize = '10px';
},1000)
}
const main = () => {
try {
const hls = new Hls({
pLoader: pLoaderAutoRefresh(TOKEN_LIFETIME)
});
hls.on(Hls.Events.MANIFEST_LOADED, (event, data) => {
console.log('1. manifest loaded:', event, data);
video.play();
})
hls.on(Hls.Events.MEDIA_ATTACHED, (event, data) => {
console.log('2. media attached:', event, data)
})
hls.on(Hls.Events.LEVEL_LOADING, (event, data) => {
console.log('3. level loading:', event, data);
})
hls.on(Hls.Events.LEVEL_LOADED, (event, data) => {
console.log('4. level loaded:', event, data);
writeMessage(`current token = ${getParam(data.details.url, 'token')}`);
})
hls.attachMedia(video);
getPlaylistUrl()
.then(url => hls.loadSource(url))
} catch(err) {
console.error(err)
}
}
main()