nuvio-tizen 1.8.11 → 1.8.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nuvio-tizen might be problematic. Click here for more details.
- package/config.xml +1 -1
- package/index.html +9 -9
- package/js/player.js +43 -5
- package/js/views.js +8 -2
- package/package.json +1 -1
package/config.xml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
2
|
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:tizen="http://tizen.org/ns/widgets"
|
|
3
|
-
id="http://nuvio.tizen/NuvioTizen" version="1.8.
|
|
3
|
+
id="http://nuvio.tizen/NuvioTizen" version="1.8.13" viewmodes="maximized">
|
|
4
4
|
<tizen:application id="Nuvio00001.Nuvio" package="Nuvio00001" required_version="2.4"/>
|
|
5
5
|
<content src="index.html"/>
|
|
6
6
|
<feature name="http://tizen.org/feature/screen.size.all"/>
|
package/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=1920, height=1080, user-scalable=no">
|
|
6
6
|
<title>Nuvio</title>
|
|
7
|
-
<link rel="stylesheet" href="css/style.css?v=1.8.
|
|
7
|
+
<link rel="stylesheet" href="css/style.css?v=1.8.13">
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<!-- CSS-applied sentinel (kept off-screen); app.js waits for its width before rendering -->
|
|
@@ -47,13 +47,13 @@
|
|
|
47
47
|
|
|
48
48
|
<!-- Load order matters: polyfills -> util -> data -> input -> player -> views -> app -->
|
|
49
49
|
<!-- ?v= busts the TV webview cache on every release (keep in sync with package.json) -->
|
|
50
|
-
<script src="js/polyfills.js?v=1.8.
|
|
51
|
-
<script src="js/util.js?v=1.8.
|
|
52
|
-
<script src="js/stremio.js?v=1.8.
|
|
53
|
-
<script src="js/keys.js?v=1.8.
|
|
54
|
-
<script src="js/focus.js?v=1.8.
|
|
55
|
-
<script src="js/player.js?v=1.8.
|
|
56
|
-
<script src="js/views.js?v=1.8.
|
|
57
|
-
<script src="js/app.js?v=1.8.
|
|
50
|
+
<script src="js/polyfills.js?v=1.8.13"></script>
|
|
51
|
+
<script src="js/util.js?v=1.8.13"></script>
|
|
52
|
+
<script src="js/stremio.js?v=1.8.13"></script>
|
|
53
|
+
<script src="js/keys.js?v=1.8.13"></script>
|
|
54
|
+
<script src="js/focus.js?v=1.8.13"></script>
|
|
55
|
+
<script src="js/player.js?v=1.8.13"></script>
|
|
56
|
+
<script src="js/views.js?v=1.8.13"></script>
|
|
57
|
+
<script src="js/app.js?v=1.8.13"></script>
|
|
58
58
|
</body>
|
|
59
59
|
</html>
|
package/js/player.js
CHANGED
|
@@ -54,6 +54,12 @@ var Player = (function () {
|
|
|
54
54
|
var _barOpen = false;
|
|
55
55
|
var _barIdx = 0;
|
|
56
56
|
|
|
57
|
+
// seek robustness (AVPlay can error if you seek mid-buffer)
|
|
58
|
+
var _buffering = false;
|
|
59
|
+
var _pendingSeek = null;
|
|
60
|
+
var _lastSeekAt = 0;
|
|
61
|
+
var _seekRecovering = false;
|
|
62
|
+
|
|
57
63
|
var _active = false;
|
|
58
64
|
var _onExit = null;
|
|
59
65
|
var _ctx = null; // { id, type, name, poster, resumeSec }
|
|
@@ -161,6 +167,7 @@ var Player = (function () {
|
|
|
161
167
|
_audioIdx = null;
|
|
162
168
|
_menuOpen = false; _barOpen = false;
|
|
163
169
|
_segments = null; _creditsSec = null; _creditsHandled = false; _segShown = {};
|
|
170
|
+
_buffering = false; _pendingSeek = null; _lastSeekAt = 0; _seekRecovering = false;
|
|
164
171
|
hideSkip();
|
|
165
172
|
subsEl.className = 'hidden'; U.clear(subsEl);
|
|
166
173
|
subMenuEl.className = 'hidden';
|
|
@@ -222,11 +229,26 @@ var Player = (function () {
|
|
|
222
229
|
try {
|
|
223
230
|
avplay.open(url);
|
|
224
231
|
avplay.setListener({
|
|
225
|
-
onbufferingstart: function () { U.spinner(true); },
|
|
226
|
-
onbufferingcomplete: function () {
|
|
232
|
+
onbufferingstart: function () { _buffering = true; U.spinner(true); },
|
|
233
|
+
onbufferingcomplete: function () {
|
|
234
|
+
_buffering = false; U.spinner(false);
|
|
235
|
+
if (_pendingSeek != null) { var pt = _pendingSeek; _pendingSeek = null; doAVSeek(pt, 0); }
|
|
236
|
+
},
|
|
227
237
|
onstreamcompleted: function () { _cur = _dur; onEnded(); },
|
|
228
238
|
oncurrentplaytime: function (ms) { _cur = ms / 1000; onProgress(); },
|
|
229
|
-
onerror: function (err) {
|
|
239
|
+
onerror: function (err) {
|
|
240
|
+
U.spinner(false);
|
|
241
|
+
// A seek can throw a transient error on some HLS streams. If we just
|
|
242
|
+
// sought, try to recover (resume) instead of ending playback.
|
|
243
|
+
if (Date.now() - _lastSeekAt < 6000 && !_seekRecovering) {
|
|
244
|
+
_seekRecovering = true;
|
|
245
|
+
try { avplay.play(); } catch (e) {}
|
|
246
|
+
setTimeout(function () { _seekRecovering = false; }, 4000);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
U.toast('Playback error: ' + err);
|
|
250
|
+
setTimeout(exit, 1500);
|
|
251
|
+
}
|
|
230
252
|
});
|
|
231
253
|
try { avplay.setStreamingProperty('ADAPTIVE_INFO', 'BITRATES=1'); } catch (e0) {}
|
|
232
254
|
avplay.prepareAsync(function () {
|
|
@@ -395,17 +417,33 @@ var Player = (function () {
|
|
|
395
417
|
|
|
396
418
|
function seekTo(sec) {
|
|
397
419
|
if (_isLive) { showOSD(false); U.toast('Live — seeking unavailable', 1500); return; }
|
|
398
|
-
|
|
420
|
+
// keep a small margin from the very end (seeking to EOF can error)
|
|
421
|
+
var maxT = _dur ? Math.max(0, _dur - 2) : 1e9;
|
|
422
|
+
var target = Math.max(0, Math.min(maxT, sec));
|
|
399
423
|
_cur = target;
|
|
400
424
|
renderOSD();
|
|
401
425
|
showOSD(false);
|
|
402
426
|
if (useAV) {
|
|
403
|
-
|
|
427
|
+
// Don't seek while buffering — queue it until buffering completes.
|
|
428
|
+
if (_buffering) { _pendingSeek = target; U.spinner(true); return; }
|
|
429
|
+
doAVSeek(target, 0);
|
|
404
430
|
} else {
|
|
405
431
|
try { videoEl.currentTime = target; } catch (e2) {}
|
|
406
432
|
}
|
|
407
433
|
}
|
|
408
434
|
|
|
435
|
+
// Seek only when AVPlay is in a seekable state; retry briefly otherwise.
|
|
436
|
+
function doAVSeek(targetSec, attempt) {
|
|
437
|
+
_lastSeekAt = Date.now();
|
|
438
|
+
var st = '';
|
|
439
|
+
try { st = avplay.getState(); } catch (e) {}
|
|
440
|
+
if (st === 'PLAYING' || st === 'PAUSED' || st === 'READY') {
|
|
441
|
+
try { avplay.seekTo(Math.floor(targetSec * 1000)); } catch (e2) { /* non-fatal */ }
|
|
442
|
+
} else if (attempt < 4 && _active) {
|
|
443
|
+
setTimeout(function () { if (_active) { doAVSeek(targetSec, attempt + 1); } }, 350);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
409
447
|
function seekBy(delta) { seekTo(_cur + delta); }
|
|
410
448
|
|
|
411
449
|
// ---------- subtitles ----------
|
package/js/views.js
CHANGED
|
@@ -655,9 +655,11 @@ var Views = (function () {
|
|
|
655
655
|
var cancelBtn = U.el('div', 'pill focusable', 'Cancel');
|
|
656
656
|
confirmBtn.__onselect = doConfirm;
|
|
657
657
|
cancelBtn.__onselect = function () { App.back(); };
|
|
658
|
-
|
|
658
|
+
|
|
659
|
+
// Order: Validate · Confirm · Cancel
|
|
660
|
+
var valBtn = null;
|
|
659
661
|
if (cfg.validator) {
|
|
660
|
-
|
|
662
|
+
valBtn = U.el('div', 'pill focusable', 'Validate');
|
|
661
663
|
valBtn.__onselect = function () {
|
|
662
664
|
var v = ('' + input.value).trim();
|
|
663
665
|
if (!v) { U.toast('Enter a key first'); return; }
|
|
@@ -668,9 +670,13 @@ var Views = (function () {
|
|
|
668
670
|
};
|
|
669
671
|
row.appendChild(valBtn);
|
|
670
672
|
}
|
|
673
|
+
row.appendChild(confirmBtn);
|
|
671
674
|
row.appendChild(cancelBtn);
|
|
672
675
|
wrap.appendChild(row);
|
|
673
676
|
|
|
677
|
+
// DOWN from the field lands on Validate (or Confirm when there's no validator)
|
|
678
|
+
input.__navDOWN = function () { Focus.setFocus(valBtn || confirmBtn); return true; };
|
|
679
|
+
|
|
674
680
|
s.appendChild(wrap);
|
|
675
681
|
Focus.setScope(s, input);
|
|
676
682
|
|