@@ -111,82 +111,130 @@ document.addEventListener('DOMContentLoaded', function() {
111111 logMsg ( 'video error: code ' + ( err ? err . code : 'unknown' ) + ', msg: ' + ( err ? err . message : 'unknown' ) ) ;
112112 } ) ;
113113
114- if ( Hls . isSupported ( ) ) {
115- logMsg ( 'hls.js supported' ) ;
116- var hls = new Hls ( {
117- debug : false ,
118- maxBufferLength : 60 ,
119- maxMaxBufferLength : 120 ,
120- maxBufferHole : 0.5 ,
121- startPosition : 0 ,
122- nudgeMaxRetry : 5 ,
123- } ) ;
124- hls . loadSource ( videoSrc ) ;
125- hls . attachMedia ( video ) ;
126-
127- hls . on ( Hls . Events . MANIFEST_PARSED , function ( ) {
128- logMsg ( 'hls: manifest parsed, playing' ) ;
129- video . play ( ) ;
114+ function getHash ( str ) {
115+ if ( crypto && crypto . subtle ) {
116+ return crypto . subtle . digest ( 'SHA-256' , new TextEncoder ( ) . encode ( str ) ) . then ( function ( buf ) {
117+ return Array . from ( new Uint8Array ( buf ) ) . map ( function ( b ) { return b . toString ( 16 ) . padStart ( 2 , '0' ) ; } ) . join ( '' ) ;
118+ } ) ;
119+ }
120+ return new Promise ( function ( resolve ) {
121+ var hash = 0 ;
122+ for ( var i = 0 ; i < str . length ; i ++ ) hash = ( ( hash << 5 ) - hash ) + str . charCodeAt ( i ) | 0 ;
123+ resolve ( hash . toString ( 36 ) ) ;
130124 } ) ;
125+ }
131126
132- hls . on ( Hls . Events . ERROR , function ( event , data ) {
133- var msg = 'hls error: type=' + data . type + ', details=' + data . details + ', fatal=' + data . fatal ;
134- logMsg ( msg ) ;
135- if ( data . fatal ) {
136- switch ( data . type ) {
137- case Hls . ErrorTypes . NETWORK_ERROR :
138- logMsg ( 'hls: fatal network error, trying to recover' ) ;
139- hls . startLoad ( ) ;
140- break ;
141- case Hls . ErrorTypes . MEDIA_ERROR :
142- logMsg ( 'hls: fatal media error, trying to recover' ) ;
143- hls . recoverMediaError ( ) ;
144- break ;
145- default :
146- logMsg ( 'hls: unrecoverable fatal error' ) ;
147- hls . destroy ( ) ;
148- break ;
127+ var tsSrc = urlParams . get ( 't' ) || '0' ;
128+ getHash ( videoSrc + '_' + tsSrc ) . then ( function ( hk ) {
129+ var hashKey = 'lws_hls_' + hk ;
130+ var startPos = 0 ;
131+
132+ try {
133+ var saved = localStorage . getItem ( hashKey ) ;
134+ if ( saved ) {
135+ var parsed = JSON . parse ( saved ) ;
136+ if ( Date . now ( ) - parsed . ts < 604800000 ) { // 1 week
137+ startPos = parsed . pos ;
138+ logMsg ( 'resuming from ' + startPos . toFixed ( 1 ) + 's' ) ;
139+ } else {
140+ localStorage . removeItem ( hashKey ) ;
149141 }
150142 }
151- } ) ;
143+ } catch ( e ) { }
152144
153- hls . on ( Hls . Events . BUFFER_APPENDED , function ( ) {
154- if ( video . buffered . length > 0 ) {
155- var ranges = [ ] ;
156- for ( var i = 0 ; i < video . buffered . length ; i ++ ) {
157- ranges . push ( '[' + video . buffered . start ( i ) . toFixed ( 1 ) + 's - ' + video . buffered . end ( i ) . toFixed ( 1 ) + 's]' ) ;
158- }
159- logMsg ( 'buffer: ' + ranges . join ( ', ' ) ) ;
145+ video . addEventListener ( 'timeupdate' , function ( ) {
146+ if ( ! video . duration || isNaN ( video . duration ) ) return ;
147+ var pct = video . currentTime / video . duration ;
148+ if ( pct >= 0.95 ) {
149+ localStorage . removeItem ( hashKey ) ;
150+ } else if ( video . currentTime > 0 ) {
151+ localStorage . setItem ( hashKey , JSON . stringify ( {
152+ pos : video . currentTime ,
153+ ts : Date . now ( )
154+ } ) ) ;
160155 }
161156 } ) ;
162- hls . on ( Hls . Events . FRAG_LOADING , function ( event , data ) {
163- if ( data . frag ) {
164- logMsg ( 'loading seg ' + data . frag . sn + ' (' + data . frag . start . toFixed ( 1 ) + 's - ' + ( data . frag . start + data . frag . duration ) . toFixed ( 1 ) + 's)' ) ;
165- }
166- } ) ;
167- }
168- // For Safari, which natively supports HLS
169- else if ( video . canPlayType ( 'application/vnd.apple.mpegurl' ) ) {
170- logMsg ( 'native HLS supported' ) ;
171- video . src = videoSrc ;
172- video . addEventListener ( 'loadedmetadata' , function ( ) {
173- logMsg ( 'native HLS metadata loaded, playing' ) ;
174- video . play ( ) ;
175- } ) ;
176157
177- // Polling buffer status for native HLS
178- setInterval ( function ( ) {
179- if ( video . buffered . length > 0 ) {
180- var ranges = [ ] ;
181- for ( var i = 0 ; i < video . buffered . length ; i ++ ) {
182- ranges . push ( '[' + video . buffered . start ( i ) . toFixed ( 1 ) + 's - ' + video . buffered . end ( i ) . toFixed ( 1 ) + 's]' ) ;
158+ if ( Hls . isSupported ( ) ) {
159+ logMsg ( 'hls.js supported' ) ;
160+ var hls = new Hls ( {
161+ debug : false ,
162+ maxBufferLength : 60 ,
163+ maxMaxBufferLength : 120 ,
164+ maxBufferHole : 0.5 ,
165+ startPosition : startPos ,
166+ nudgeMaxRetry : 5 ,
167+ } ) ;
168+ hls . loadSource ( videoSrc ) ;
169+ hls . attachMedia ( video ) ;
170+
171+ hls . on ( Hls . Events . MANIFEST_PARSED , function ( ) {
172+ logMsg ( 'hls: manifest parsed, playing' ) ;
173+ video . play ( ) ;
174+ } ) ;
175+
176+ hls . on ( Hls . Events . ERROR , function ( event , data ) {
177+ var msg = 'hls error: type=' + data . type + ', details=' + data . details + ', fatal=' + data . fatal ;
178+ logMsg ( msg ) ;
179+ if ( data . fatal ) {
180+ switch ( data . type ) {
181+ case Hls . ErrorTypes . NETWORK_ERROR :
182+ logMsg ( 'hls: fatal network error, trying to recover' ) ;
183+ hls . startLoad ( ) ;
184+ break ;
185+ case Hls . ErrorTypes . MEDIA_ERROR :
186+ logMsg ( 'hls: fatal media error, trying to recover' ) ;
187+ hls . recoverMediaError ( ) ;
188+ break ;
189+ default :
190+ logMsg ( 'hls: unrecoverable fatal error' ) ;
191+ hls . destroy ( ) ;
192+ break ;
193+ }
183194 }
184- logMsg ( 'native buffer: ' + ranges . join ( ', ' ) ) ;
185- }
186- } , 2000 ) ;
187- }
188- else {
189- logMsg ( 'error: browser does not support HLS' ) ;
190- alert ( "Your browser does not support playing this video." ) ;
191- }
195+ } ) ;
196+
197+ hls . on ( Hls . Events . BUFFER_APPENDED , function ( ) {
198+ if ( video . buffered . length > 0 ) {
199+ var ranges = [ ] ;
200+ for ( var i = 0 ; i < video . buffered . length ; i ++ ) {
201+ ranges . push ( '[' + video . buffered . start ( i ) . toFixed ( 1 ) + 's - ' + video . buffered . end ( i ) . toFixed ( 1 ) + 's]' ) ;
202+ }
203+ logMsg ( 'buffer: ' + ranges . join ( ', ' ) ) ;
204+ }
205+ } ) ;
206+ hls . on ( Hls . Events . FRAG_LOADING , function ( event , data ) {
207+ if ( data . frag ) {
208+ logMsg ( 'loading seg ' + data . frag . sn + ' (' + data . frag . start . toFixed ( 1 ) + 's - ' + ( data . frag . start + data . frag . duration ) . toFixed ( 1 ) + 's)' ) ;
209+ }
210+ } ) ;
211+ }
212+ // For Safari, which natively supports HLS
213+ else if ( video . canPlayType ( 'application/vnd.apple.mpegurl' ) ) {
214+ logMsg ( 'native HLS supported' ) ;
215+ video . src = videoSrc ;
216+ video . addEventListener ( 'loadedmetadata' , function ( ) {
217+ logMsg ( 'native HLS metadata loaded, playing' ) ;
218+ if ( startPos > 0 ) {
219+ video . currentTime = startPos ;
220+ }
221+ video . play ( ) ;
222+ } ) ;
223+
224+ // Polling buffer status for native HLS
225+ setInterval ( function ( ) {
226+ if ( video . buffered . length > 0 ) {
227+ var ranges = [ ] ;
228+ for ( var i = 0 ; i < video . buffered . length ; i ++ ) {
229+ ranges . push ( '[' + video . buffered . start ( i ) . toFixed ( 1 ) + 's - ' + video . buffered . end ( i ) . toFixed ( 1 ) + 's]' ) ;
230+ }
231+ logMsg ( 'native buffer: ' + ranges . join ( ', ' ) ) ;
232+ }
233+ } , 2000 ) ;
234+ }
235+ else {
236+ logMsg ( 'error: browser does not support HLS' ) ;
237+ alert ( "Your browser does not support playing this video." ) ;
238+ }
239+ } ) ;
192240} ) ;
0 commit comments